ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

rpcserver.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:     ReactOS Service Control Manager
00003  * LICENSE:     GPL - See COPYING in the top level directory
00004  * FILE:        base/system/services/rpcserver.c
00005  * PURPOSE:     RPC server interface for the advapi32 calls
00006  * COPYRIGHT:   Copyright 2005-2006 Eric Kohl
00007  *              Copyright 2006-2007 Hervé Poussineau <hpoussin@reactos.org>
00008  *              Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
00009  */
00010 
00011 /* INCLUDES ****************************************************************/
00012 
00013 #include "services.h"
00014 
00015 #define NDEBUG
00016 #include <debug.h>
00017 
00018 /* GLOBALS *****************************************************************/
00019 
00020 #define MANAGER_TAG 0x72674D68  /* 'hMgr' */
00021 #define SERVICE_TAG 0x63765368  /* 'hSvc' */
00022 
00023 typedef struct _SCMGR_HANDLE
00024 {
00025     DWORD Tag;
00026     DWORD DesiredAccess;
00027 } SCMGR_HANDLE;
00028 
00029 
00030 typedef struct _MANAGER_HANDLE
00031 {
00032     SCMGR_HANDLE Handle;
00033     WCHAR DatabaseName[1];
00034 } MANAGER_HANDLE, *PMANAGER_HANDLE;
00035 
00036 
00037 typedef struct _SERVICE_HANDLE
00038 {
00039     SCMGR_HANDLE Handle;
00040     PSERVICE ServiceEntry;
00041 } SERVICE_HANDLE, *PSERVICE_HANDLE;
00042 
00043 
00044 #define SC_MANAGER_READ \
00045   (STANDARD_RIGHTS_READ | \
00046    SC_MANAGER_QUERY_LOCK_STATUS | \
00047    SC_MANAGER_ENUMERATE_SERVICE)
00048 
00049 #define SC_MANAGER_WRITE \
00050   (STANDARD_RIGHTS_WRITE | \
00051    SC_MANAGER_MODIFY_BOOT_CONFIG | \
00052    SC_MANAGER_CREATE_SERVICE)
00053 
00054 #define SC_MANAGER_EXECUTE \
00055   (STANDARD_RIGHTS_EXECUTE | \
00056    SC_MANAGER_LOCK | \
00057    SC_MANAGER_ENUMERATE_SERVICE | \
00058    SC_MANAGER_CONNECT | \
00059    SC_MANAGER_CREATE_SERVICE)
00060 
00061 
00062 #define SERVICE_READ \
00063   (STANDARD_RIGHTS_READ | \
00064    SERVICE_INTERROGATE | \
00065    SERVICE_ENUMERATE_DEPENDENTS | \
00066    SERVICE_QUERY_STATUS | \
00067    SERVICE_QUERY_CONFIG)
00068 
00069 #define SERVICE_WRITE \
00070   (STANDARD_RIGHTS_WRITE | \
00071    SERVICE_CHANGE_CONFIG)
00072 
00073 #define SERVICE_EXECUTE \
00074   (STANDARD_RIGHTS_EXECUTE | \
00075    SERVICE_USER_DEFINED_CONTROL | \
00076    SERVICE_PAUSE_CONTINUE | \
00077    SERVICE_STOP | \
00078    SERVICE_START)
00079 
00080 #define TAG_ARRAY_SIZE 32
00081 
00082 /* VARIABLES ***************************************************************/
00083 
00084 static GENERIC_MAPPING
00085 ScmManagerMapping = {SC_MANAGER_READ,
00086                      SC_MANAGER_WRITE,
00087                      SC_MANAGER_EXECUTE,
00088                      SC_MANAGER_ALL_ACCESS};
00089 
00090 static GENERIC_MAPPING
00091 ScmServiceMapping = {SERVICE_READ,
00092                      SERVICE_WRITE,
00093                      SERVICE_EXECUTE,
00094                      SERVICE_ALL_ACCESS};
00095 
00096 
00097 /* FUNCTIONS ***************************************************************/
00098 
00099 VOID
00100 ScmStartRpcServer(VOID)
00101 {
00102     RPC_STATUS Status;
00103 
00104     DPRINT("ScmStartRpcServer() called\n");
00105 
00106     Status = RpcServerUseProtseqEpW(L"ncacn_np",
00107                                     10,
00108                                     L"\\pipe\\ntsvcs",
00109                                     NULL);
00110     if (Status != RPC_S_OK)
00111     {
00112         DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
00113         return;
00114     }
00115 
00116     Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
00117                                  NULL,
00118                                  NULL);
00119     if (Status != RPC_S_OK)
00120     {
00121         DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
00122         return;
00123     }
00124 
00125     Status = RpcServerListen(1, 20, TRUE);
00126     if (Status != RPC_S_OK)
00127     {
00128         DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
00129         return;
00130     }
00131 
00132     DPRINT("ScmStartRpcServer() done\n");
00133 }
00134 
00135 
00136 static DWORD
00137 ScmCreateManagerHandle(LPWSTR lpDatabaseName,
00138                        SC_HANDLE *Handle)
00139 {
00140     PMANAGER_HANDLE Ptr;
00141 
00142     if (lpDatabaseName == NULL)
00143         lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
00144 
00145     if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
00146     {
00147         DPRINT("Database %S, does not exist\n", lpDatabaseName);
00148         return ERROR_DATABASE_DOES_NOT_EXIST;
00149     }
00150     else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
00151     {
00152         DPRINT("Invalid Database name %S.\n", lpDatabaseName);
00153         return ERROR_INVALID_NAME;
00154     }
00155 
00156     Ptr = HeapAlloc(GetProcessHeap(),
00157                     HEAP_ZERO_MEMORY,
00158                     FIELD_OFFSET(MANAGER_HANDLE, DatabaseName[wcslen(lpDatabaseName) + 1]));
00159     if (Ptr == NULL)
00160         return ERROR_NOT_ENOUGH_MEMORY;
00161 
00162     Ptr->Handle.Tag = MANAGER_TAG;
00163 
00164     wcscpy(Ptr->DatabaseName, lpDatabaseName);
00165 
00166     *Handle = (SC_HANDLE)Ptr;
00167 
00168     return ERROR_SUCCESS;
00169 }
00170 
00171 
00172 static DWORD
00173 ScmCreateServiceHandle(PSERVICE lpServiceEntry,
00174                        SC_HANDLE *Handle)
00175 {
00176     PSERVICE_HANDLE Ptr;
00177 
00178     Ptr = HeapAlloc(GetProcessHeap(),
00179                     HEAP_ZERO_MEMORY,
00180                     sizeof(SERVICE_HANDLE));
00181     if (Ptr == NULL)
00182         return ERROR_NOT_ENOUGH_MEMORY;
00183 
00184     Ptr->Handle.Tag = SERVICE_TAG;
00185 
00186     Ptr->ServiceEntry = lpServiceEntry;
00187 
00188     *Handle = (SC_HANDLE)Ptr;
00189 
00190     return ERROR_SUCCESS;
00191 }
00192 
00193 
00194 static PMANAGER_HANDLE
00195 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle)
00196 {
00197     PMANAGER_HANDLE pManager = NULL;
00198 
00199     _SEH2_TRY
00200     {
00201         if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG)
00202             pManager = (PMANAGER_HANDLE)Handle;
00203     }
00204     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00205     {
00206         DPRINT1("Exception: Invalid Service Manager handle!\n");
00207     }
00208     _SEH2_END;
00209 
00210     return pManager;
00211 }
00212 
00213 
00214 static PSERVICE_HANDLE
00215 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle)
00216 {
00217     PSERVICE_HANDLE pService = NULL;
00218 
00219     _SEH2_TRY
00220     {
00221         if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG)
00222             pService = (PSERVICE_HANDLE)Handle;
00223     }
00224     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00225     {
00226         DPRINT1("Exception: Invalid Service handle!\n");
00227     }
00228     _SEH2_END;
00229 
00230     return pService;
00231 }
00232 
00233 
00234 static DWORD
00235 ScmCheckAccess(SC_HANDLE Handle,
00236                DWORD dwDesiredAccess)
00237 {
00238     PMANAGER_HANDLE hMgr;
00239 
00240     hMgr = (PMANAGER_HANDLE)Handle;
00241     if (hMgr->Handle.Tag == MANAGER_TAG)
00242     {
00243         RtlMapGenericMask(&dwDesiredAccess,
00244                           &ScmManagerMapping);
00245 
00246         hMgr->Handle.DesiredAccess = dwDesiredAccess;
00247 
00248         return ERROR_SUCCESS;
00249     }
00250     else if (hMgr->Handle.Tag == SERVICE_TAG)
00251     {
00252         RtlMapGenericMask(&dwDesiredAccess,
00253                           &ScmServiceMapping);
00254 
00255         hMgr->Handle.DesiredAccess = dwDesiredAccess;
00256 
00257         return ERROR_SUCCESS;
00258     }
00259 
00260     return ERROR_INVALID_HANDLE;
00261 }
00262 
00263 
00264 DWORD
00265 ScmAssignNewTag(PSERVICE lpService)
00266 {
00267     HKEY hKey = NULL;
00268     DWORD dwError;
00269     DWORD dwGroupTagCount = 0;
00270     PDWORD pdwGroupTags = NULL;
00271     DWORD dwFreeTag = 0;
00272     DWORD dwTagUsedBase = 1;
00273     BOOLEAN TagUsed[TAG_ARRAY_SIZE];
00274     INT nTagOffset;
00275     DWORD i;
00276     DWORD cbDataSize;
00277     PLIST_ENTRY ServiceEntry;
00278     PSERVICE CurrentService;
00279 
00280     ASSERT(lpService != NULL);
00281     ASSERT(lpService->lpGroup != NULL);
00282 
00283     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
00284                             L"System\\CurrentControlSet\\Control\\GroupOrderList",
00285                             0,
00286                             KEY_READ,
00287                             &hKey);
00288 
00289     if (dwError != ERROR_SUCCESS)
00290         goto findFreeTag;
00291 
00292     /* query value length */
00293     cbDataSize = 0;
00294     dwError = RegQueryValueExW(hKey,
00295                                lpService->lpGroup->szGroupName,
00296                                NULL,
00297                                NULL,
00298                                NULL,
00299                                &cbDataSize);
00300 
00301     if (dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA)
00302         goto findFreeTag;
00303 
00304     pdwGroupTags = HeapAlloc(GetProcessHeap(), 0, cbDataSize);
00305     if (!pdwGroupTags)
00306     {
00307         dwError = ERROR_NOT_ENOUGH_MEMORY;
00308         goto cleanup;
00309     }
00310 
00311     dwError = RegQueryValueExW(hKey,
00312                                lpService->lpGroup->szGroupName,
00313                                NULL,
00314                                NULL,
00315                                (LPBYTE)pdwGroupTags,
00316                                &cbDataSize);
00317 
00318     if (dwError != ERROR_SUCCESS)
00319         goto findFreeTag;
00320 
00321     if (cbDataSize < sizeof(pdwGroupTags[0]))
00322         goto findFreeTag;
00323 
00324     dwGroupTagCount = min(pdwGroupTags[0], cbDataSize / sizeof(pdwGroupTags[0]) - 1);
00325 
00326 findFreeTag:
00327     do
00328     {
00329         /* mark all tags as unused */
00330         for (i = 0; i < TAG_ARRAY_SIZE; i++)
00331             TagUsed[i] = FALSE;
00332 
00333         /* mark tags in GroupOrderList as used */
00334         for (i = 1; i <= dwGroupTagCount; i++)
00335         {
00336             nTagOffset = pdwGroupTags[i] - dwTagUsedBase;
00337             if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
00338                 TagUsed[nTagOffset] = TRUE;
00339         }
00340 
00341         /* mark tags in service list as used */
00342         ServiceEntry = lpService->ServiceListEntry.Flink;
00343         while (ServiceEntry != &lpService->ServiceListEntry)
00344         {
00345             ASSERT(ServiceEntry != NULL);
00346             CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
00347             if (CurrentService->lpGroup == lpService->lpGroup)
00348             {
00349                 nTagOffset = CurrentService->dwTag - dwTagUsedBase;
00350                 if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
00351                     TagUsed[nTagOffset] = TRUE;
00352             }
00353 
00354             ServiceEntry = ServiceEntry->Flink;
00355         }
00356 
00357         /* find unused tag, if any */
00358         for (i = 0; i < TAG_ARRAY_SIZE; i++)
00359         {
00360             if (!TagUsed[i])
00361             {
00362                 dwFreeTag = dwTagUsedBase + i;
00363                 break;
00364             }
00365         }
00366 
00367         dwTagUsedBase += TAG_ARRAY_SIZE;
00368     } while (!dwFreeTag);
00369 
00370 cleanup:
00371     if (pdwGroupTags)
00372         HeapFree(GetProcessHeap(), 0, pdwGroupTags);
00373 
00374     if (hKey)
00375         RegCloseKey(hKey);
00376 
00377     if (dwFreeTag)
00378     {
00379         lpService->dwTag = dwFreeTag;
00380         DPRINT("Assigning new tag %lu to service %S in group %S\n",
00381                lpService->dwTag, lpService->lpServiceName, lpService->lpGroup->szGroupName);
00382         dwError = ERROR_SUCCESS;
00383     }
00384     else
00385     {
00386         DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
00387                 lpService->lpServiceName, dwError);
00388     }
00389 
00390     return dwError;
00391 }
00392 
00393 
00394 /* Create a path suitable for the bootloader out of the full path */
00395 DWORD
00396 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
00397 {
00398     DWORD ServiceNameLen, BufferSize, ExpandedLen;
00399     WCHAR Dest;
00400     WCHAR *Expanded;
00401     UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
00402     OBJECT_ATTRIBUTES ObjectAttributes;
00403     NTSTATUS Status;
00404     HANDLE SymbolicLinkHandle;
00405 
00406     DPRINT("ScmConvertToBootPathName %S\n", CanonName);
00407 
00408     ServiceNameLen = wcslen(CanonName);
00409 
00410     /* First check, if it's already good */
00411     if (ServiceNameLen > 12 &&
00412         !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
00413     {
00414         *RelativeName = HeapAlloc(GetProcessHeap(),
00415                                   HEAP_ZERO_MEMORY,
00416                                   (ServiceNameLen + 1) * sizeof(WCHAR));
00417         if (*RelativeName == NULL)
00418         {
00419             DPRINT("Error allocating memory for boot driver name!\n");
00420             return ERROR_NOT_ENOUGH_MEMORY;
00421         }
00422 
00423         /* Copy it */
00424         wcscpy(*RelativeName, CanonName);
00425 
00426         DPRINT("Bootdriver name %S\n", *RelativeName);
00427         return ERROR_SUCCESS;
00428     }
00429 
00430     /* If it has %SystemRoot% prefix, substitute it to \System*/
00431     if (ServiceNameLen > 13 &&
00432         !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
00433     {
00434         /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
00435         *RelativeName = HeapAlloc(GetProcessHeap(),
00436                                   HEAP_ZERO_MEMORY,
00437                                   ServiceNameLen * sizeof(WCHAR));
00438 
00439         if (*RelativeName == NULL)
00440         {
00441             DPRINT("Error allocating memory for boot driver name!\n");
00442             return ERROR_NOT_ENOUGH_MEMORY;
00443         }
00444 
00445         /* Copy it */
00446         wcscpy(*RelativeName, L"\\SystemRoot\\");
00447         wcscat(*RelativeName, CanonName + 13);
00448 
00449         DPRINT("Bootdriver name %S\n", *RelativeName);
00450         return ERROR_SUCCESS;
00451     }
00452 
00453     /* Get buffer size needed for expanding env strings */
00454     BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
00455 
00456     if (BufferSize <= 1)
00457     {
00458         DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
00459         return ERROR_INVALID_ENVIRONMENT;
00460     }
00461 
00462     /* Allocate memory, since the size is known now */
00463     Expanded = HeapAlloc(GetProcessHeap(),
00464                          HEAP_ZERO_MEMORY,
00465                          (BufferSize + 1) * sizeof(WCHAR));
00466     if (!Expanded)
00467     {
00468         DPRINT("Error allocating memory for boot driver name!\n");
00469         return ERROR_NOT_ENOUGH_MEMORY;
00470     }
00471 
00472     /* Expand it */
00473     if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
00474         BufferSize)
00475     {
00476         DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
00477         HeapFree(GetProcessHeap(), 0, Expanded);
00478         return ERROR_NOT_ENOUGH_MEMORY;
00479     }
00480 
00481     /* Convert to NY-style path */
00482     if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
00483     {
00484         DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
00485         return ERROR_INVALID_ENVIRONMENT;
00486     }
00487 
00488     DPRINT("Converted to NT-style %wZ\n", &NtPathName);
00489 
00490     /* No need to keep the dos-path anymore */
00491     HeapFree(GetProcessHeap(), 0, Expanded);
00492 
00493     /* Copy it to the allocated place */
00494     Expanded = HeapAlloc(GetProcessHeap(),
00495                          HEAP_ZERO_MEMORY,
00496                          NtPathName.Length + sizeof(UNICODE_NULL));
00497     if (!Expanded)
00498     {
00499             DPRINT("Error allocating memory for boot driver name!\n");
00500             return ERROR_NOT_ENOUGH_MEMORY;
00501     }
00502 
00503     ExpandedLen = NtPathName.Length / sizeof(WCHAR);
00504     wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
00505     Expanded[ExpandedLen] = UNICODE_NULL;
00506 
00507     if (ServiceNameLen > ExpandedLen &&
00508         !_wcsnicmp(Expanded, CanonName, ExpandedLen))
00509     {
00510         /* Only \SystemRoot\ is missing */
00511         *RelativeName = HeapAlloc(GetProcessHeap(),
00512                                   HEAP_ZERO_MEMORY,
00513                                   (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
00514         if (*RelativeName == NULL)
00515         {
00516             DPRINT("Error allocating memory for boot driver name!\n");
00517             HeapFree(GetProcessHeap(), 0, Expanded);
00518             return ERROR_NOT_ENOUGH_MEMORY;
00519         }
00520 
00521         wcscpy(*RelativeName, L"\\SystemRoot\\");
00522         wcscat(*RelativeName, CanonName + ExpandedLen);
00523 
00524         RtlFreeUnicodeString(&NtPathName);
00525         return ERROR_SUCCESS;
00526     }
00527 
00528     /* The most complex case starts here */
00529     RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
00530     InitializeObjectAttributes(&ObjectAttributes,
00531                                &SystemRoot,
00532                                OBJ_CASE_INSENSITIVE,
00533                                NULL,
00534                                NULL);
00535 
00536     /* Open this symlink */
00537     Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
00538 
00539     if (NT_SUCCESS(Status))
00540     {
00541         LinkTarget.Length = 0;
00542         LinkTarget.MaximumLength = 0;
00543 
00544         DPRINT("Opened symbolic link object\n");
00545 
00546         Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
00547         if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
00548         {
00549             /* Check if required buffer size is sane */
00550             if (BufferSize > 0xFFFD)
00551             {
00552                 DPRINT("Too large buffer required\n");
00553                 *RelativeName = 0;
00554 
00555                 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
00556                 HeapFree(GetProcessHeap(), 0, Expanded);
00557                 return ERROR_NOT_ENOUGH_MEMORY;
00558             }
00559 
00560             /* Alloc the string */
00561             LinkTarget.Length = (USHORT)BufferSize;
00562             LinkTarget.MaximumLength = LinkTarget.Length + sizeof(UNICODE_NULL);
00563             LinkTarget.Buffer = HeapAlloc(GetProcessHeap(),
00564                                           HEAP_ZERO_MEMORY,
00565                                           LinkTarget.MaximumLength);
00566             if (!LinkTarget.Buffer)
00567             {
00568                 DPRINT("Unable to alloc buffer\n");
00569                 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
00570                 HeapFree(GetProcessHeap(), 0, Expanded);
00571                 return ERROR_NOT_ENOUGH_MEMORY;
00572             }
00573 
00574             /* Do a real query now */
00575             Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
00576             if (NT_SUCCESS(Status))
00577             {
00578                 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
00579 
00580                 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
00581                 if ((ServiceNameLen > ExpandedLen) &&
00582                     !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
00583                 {
00584                     *RelativeName = HeapAlloc(GetProcessHeap(),
00585                                               HEAP_ZERO_MEMORY,
00586                                               (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
00587 
00588                     if (*RelativeName == NULL)
00589                     {
00590                         DPRINT("Unable to alloc buffer\n");
00591                         if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
00592                         HeapFree(GetProcessHeap(), 0, Expanded);
00593                         RtlFreeUnicodeString(&NtPathName);
00594                         return ERROR_NOT_ENOUGH_MEMORY;
00595                     }
00596 
00597                     /* Copy it over, substituting the first part
00598                        with SystemRoot */
00599                     wcscpy(*RelativeName, L"\\SystemRoot\\");
00600                     wcscat(*RelativeName, CanonName+ExpandedLen+1);
00601 
00602                     /* Cleanup */
00603                     if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
00604                     HeapFree(GetProcessHeap(), 0, Expanded);
00605                     RtlFreeUnicodeString(&NtPathName);
00606 
00607                     /* Return success */
00608                     return ERROR_SUCCESS;
00609                 }
00610                 else
00611                 {
00612                     if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
00613                     HeapFree(GetProcessHeap(), 0, Expanded);
00614                     RtlFreeUnicodeString(&NtPathName);
00615                     return ERROR_INVALID_PARAMETER;
00616                 }
00617             }
00618             else
00619             {
00620                 DPRINT("Error, Status = %08X\n", Status);
00621                 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
00622                 HeapFree(GetProcessHeap(), 0, Expanded);
00623                 RtlFreeUnicodeString(&NtPathName);
00624                 return ERROR_INVALID_PARAMETER;
00625             }
00626         }
00627         else
00628         {
00629             DPRINT("Error, Status = %08X\n", Status);
00630             if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
00631             HeapFree(GetProcessHeap(), 0, Expanded);
00632             RtlFreeUnicodeString(&NtPathName);
00633             return ERROR_INVALID_PARAMETER;
00634         }
00635     }
00636     else
00637     {
00638         DPRINT("Error, Status = %08X\n", Status);
00639         HeapFree(GetProcessHeap(), 0, Expanded);
00640         return ERROR_INVALID_PARAMETER;
00641     }
00642 
00643     /* Failure */
00644     *RelativeName = NULL;
00645     return ERROR_INVALID_PARAMETER;
00646 }
00647 
00648 
00649 DWORD
00650 ScmCanonDriverImagePath(DWORD dwStartType,
00651                         const wchar_t *lpServiceName,
00652                         wchar_t **lpCanonName)
00653 {
00654     DWORD ServiceNameLen, Result;
00655     UNICODE_STRING NtServiceName;
00656     WCHAR *RelativeName;
00657     const WCHAR *SourceName = lpServiceName;
00658 
00659     /* Calculate the length of the service's name */
00660     ServiceNameLen = wcslen(lpServiceName);
00661 
00662     /* 12 is wcslen(L"\\SystemRoot\\") */
00663     if (ServiceNameLen > 12 &&
00664         !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
00665     {
00666         /* SystemRoot prefix is already included */
00667         *lpCanonName = HeapAlloc(GetProcessHeap(),
00668                                  HEAP_ZERO_MEMORY,
00669                                  (ServiceNameLen + 1) * sizeof(WCHAR));
00670 
00671         if (*lpCanonName == NULL)
00672         {
00673             DPRINT("Error allocating memory for canonized service name!\n");
00674             return ERROR_NOT_ENOUGH_MEMORY;
00675         }
00676 
00677         /* If it's a boot-time driver, it must be systemroot relative */
00678         if (dwStartType == SERVICE_BOOT_START)
00679             SourceName += 12;
00680 
00681         /* Copy it */
00682         wcscpy(*lpCanonName, SourceName);
00683 
00684         DPRINT("Canonicalized name %S\n", *lpCanonName);
00685         return NO_ERROR;
00686     }
00687 
00688     /* Check if it has %SystemRoot% (len=13) */
00689     if (ServiceNameLen > 13 &&
00690         !_wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13))
00691     {
00692         /* Substitute %SystemRoot% with \\SystemRoot\\ */
00693         *lpCanonName = HeapAlloc(GetProcessHeap(),
00694                                  HEAP_ZERO_MEMORY,
00695                                  (ServiceNameLen + 1) * sizeof(WCHAR));
00696 
00697         if (*lpCanonName == NULL)
00698         {
00699             DPRINT("Error allocating memory for canonized service name!\n");
00700             return ERROR_NOT_ENOUGH_MEMORY;
00701         }
00702 
00703         /* If it's a boot-time driver, it must be systemroot relative */
00704         if (dwStartType == SERVICE_BOOT_START)
00705             wcscpy(*lpCanonName, L"\\SystemRoot\\");
00706 
00707         wcscat(*lpCanonName, lpServiceName + 13);
00708 
00709         DPRINT("Canonicalized name %S\n", *lpCanonName);
00710         return NO_ERROR;
00711     }
00712 
00713     /* Check if it's a relative path name */
00714     if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
00715     {
00716         *lpCanonName = HeapAlloc(GetProcessHeap(),
00717                                  HEAP_ZERO_MEMORY,
00718                                  (ServiceNameLen + 1) * sizeof(WCHAR));
00719 
00720         if (*lpCanonName == NULL)
00721         {
00722             DPRINT("Error allocating memory for canonized service name!\n");
00723             return ERROR_NOT_ENOUGH_MEMORY;
00724         }
00725 
00726         /* Just copy it over without changing */
00727         wcscpy(*lpCanonName, lpServiceName);
00728 
00729         return NO_ERROR;
00730     }
00731 
00732     /* It seems to be a DOS path, convert it */
00733     if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
00734     {
00735         DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
00736         return ERROR_INVALID_PARAMETER;
00737     }
00738 
00739     *lpCanonName = HeapAlloc(GetProcessHeap(),
00740                              HEAP_ZERO_MEMORY,
00741                              NtServiceName.Length + sizeof(WCHAR));
00742 
00743     if (*lpCanonName == NULL)
00744     {
00745         DPRINT("Error allocating memory for canonized service name!\n");
00746         RtlFreeUnicodeString(&NtServiceName);
00747         return ERROR_NOT_ENOUGH_MEMORY;
00748     }
00749 
00750     /* Copy the string */
00751     wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
00752 
00753     /* The unicode string is not needed anymore */
00754     RtlFreeUnicodeString(&NtServiceName);
00755 
00756     if (dwStartType != SERVICE_BOOT_START)
00757     {
00758         DPRINT("Canonicalized name %S\n", *lpCanonName);
00759         return NO_ERROR;
00760     }
00761 
00762     /* The service is boot-started, so must be relative */
00763     Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
00764     if (Result)
00765     {
00766         /* There is a problem, free name and return */
00767         HeapFree(GetProcessHeap(), 0, *lpCanonName);
00768         DPRINT("Error converting named!\n");
00769         return Result;
00770     }
00771 
00772     ASSERT(RelativeName);
00773 
00774     /* Copy that string */
00775     wcscpy(*lpCanonName, RelativeName + 12);
00776 
00777     /* Free the allocated buffer */
00778     HeapFree(GetProcessHeap(), 0, RelativeName);
00779 
00780     DPRINT("Canonicalized name %S\n", *lpCanonName);
00781 
00782     /* Success */
00783     return NO_ERROR;
00784 }
00785 
00786 
00787 /* Internal recursive function */
00788 /* Need to search for every dependency on every service */
00789 static DWORD
00790 Int_EnumDependentServicesW(HKEY hServicesKey,
00791                            PSERVICE lpService,
00792                            DWORD dwServiceState,
00793                            PSERVICE *lpServices,
00794                            LPDWORD pcbBytesNeeded,
00795                            LPDWORD lpServicesReturned)
00796 {
00797     DWORD dwError = ERROR_SUCCESS;
00798     WCHAR szNameBuf[MAX_PATH];
00799     WCHAR szValueBuf[MAX_PATH];
00800     WCHAR *lpszNameBuf = szNameBuf;
00801     WCHAR *lpszValueBuf = szValueBuf;
00802     DWORD dwSize;
00803     DWORD dwNumSubKeys;
00804     DWORD dwIteration;
00805     PSERVICE lpCurrentService;
00806     HKEY hServiceEnumKey;
00807     DWORD dwCurrentServiceState = SERVICE_ACTIVE;
00808     DWORD dwDependServiceStrPtr = 0;
00809     DWORD dwRequiredSize = 0;
00810 
00811     /* Get the number of service keys */
00812     dwError = RegQueryInfoKeyW(hServicesKey,
00813                                NULL,
00814                                NULL,
00815                                NULL,
00816                                &dwNumSubKeys,
00817                                NULL,
00818                                NULL,
00819                                NULL,
00820                                NULL,
00821                                NULL,
00822                                NULL,
00823                                NULL);
00824     if (dwError != ERROR_SUCCESS)
00825     {
00826         DPRINT("ERROR! Unable to get number of services keys.\n");
00827         return dwError;
00828     }
00829 
00830     /* Iterate the service keys to see if another service depends on the this service */
00831     for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
00832     {
00833         dwSize = MAX_PATH;
00834         dwError = RegEnumKeyExW(hServicesKey,
00835                                 dwIteration,
00836                                 lpszNameBuf,
00837                                 &dwSize,
00838                                 NULL,
00839                                 NULL,
00840                                 NULL,
00841                                 NULL);
00842         if (dwError != ERROR_SUCCESS)
00843             return dwError;
00844 
00845         /* Open the Service key */
00846         dwError = RegOpenKeyExW(hServicesKey,
00847                                 lpszNameBuf,
00848                                 0,
00849                                 KEY_READ,
00850                                 &hServiceEnumKey);
00851         if (dwError != ERROR_SUCCESS)
00852             return dwError;
00853 
00854         dwSize = MAX_PATH;
00855 
00856         /* Check for the DependOnService Value */
00857         dwError = RegQueryValueExW(hServiceEnumKey,
00858                                    L"DependOnService",
00859                                    NULL,
00860                                    NULL,
00861                                    (LPBYTE)lpszValueBuf,
00862                                    &dwSize);
00863 
00864         /* FIXME: Handle load order. */
00865 
00866         /* If the service found has a DependOnService value */
00867         if (dwError == ERROR_SUCCESS)
00868         {
00869             dwDependServiceStrPtr = 0;
00870 
00871             /* Can be more than one Dependencies in the DependOnService string */
00872             while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
00873             {
00874                 if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
00875                 {
00876                     /* Get the current enumed service pointer */
00877                     lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
00878 
00879                     /* Check for valid Service */
00880                     if (!lpCurrentService)
00881                     {
00882                         /* This should never happen! */
00883                         DPRINT("This should not happen at this point, report to Developer\n");
00884                         return ERROR_NOT_FOUND;
00885                     }
00886 
00887                     /* Determine state the service is in */
00888                     if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
00889                         dwCurrentServiceState = SERVICE_INACTIVE;
00890 
00891                     /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
00892                     if ((dwCurrentServiceState == dwServiceState) ||
00893                         (dwServiceState == SERVICE_STATE_ALL))
00894                     {
00895                         /* Calculate the required size */
00896                         dwRequiredSize += sizeof(SERVICE_STATUS);
00897                         dwRequiredSize += ((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
00898                         dwRequiredSize += ((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
00899 
00900                         /* Add the size for service name and display name pointers */
00901                         dwRequiredSize += (2 * sizeof(PVOID));
00902 
00903                         /* increase the BytesNeeded size */
00904                         *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
00905 
00906                         /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
00907                            comes first */
00908 
00909                         /* Recursive call to check for its dependencies */
00910                         Int_EnumDependentServicesW(hServicesKey,
00911                                                    lpCurrentService,
00912                                                    dwServiceState,
00913                                                    lpServices,
00914                                                    pcbBytesNeeded,
00915                                                    lpServicesReturned);
00916 
00917                         /* If the lpServices is valid set the service pointer */
00918                         if (lpServices)
00919                             lpServices[*lpServicesReturned] = lpCurrentService;
00920 
00921                         *lpServicesReturned = *lpServicesReturned + 1;
00922                     }
00923                 }
00924 
00925                 dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
00926             }
00927         }
00928         else if (*pcbBytesNeeded)
00929         {
00930             dwError = ERROR_SUCCESS;
00931         }
00932 
00933         RegCloseKey(hServiceEnumKey);
00934     }
00935 
00936     return dwError;
00937 }
00938 
00939 
00940 /* Function 0 */
00941 DWORD RCloseServiceHandle(
00942     LPSC_RPC_HANDLE hSCObject)
00943 {
00944     PMANAGER_HANDLE hManager;
00945     PSERVICE_HANDLE hService;
00946     PSERVICE lpService;
00947     HKEY hServicesKey;
00948     DWORD dwError;
00949     DWORD pcbBytesNeeded = 0;
00950     DWORD dwServicesReturned = 0;
00951 
00952     DPRINT("RCloseServiceHandle() called\n");
00953 
00954     DPRINT("hSCObject = %p\n", *hSCObject);
00955 
00956     if (*hSCObject == 0)
00957         return ERROR_INVALID_HANDLE;
00958 
00959     hManager = ScmGetServiceManagerFromHandle(*hSCObject);
00960     hService = ScmGetServiceFromHandle(*hSCObject);
00961 
00962     if (hManager != NULL)
00963     {
00964         DPRINT("Found manager handle\n");
00965 
00966         /* FIXME: add handle cleanup code */
00967 
00968         HeapFree(GetProcessHeap(), 0, hManager);
00969         hManager = NULL;
00970 
00971         *hSCObject = NULL;
00972 
00973         DPRINT("RCloseServiceHandle() done\n");
00974         return ERROR_SUCCESS;
00975     }
00976     else if (hService != NULL)
00977     {
00978         DPRINT("Found service handle\n");
00979 
00980         /* Lock the service database exlusively */
00981         ScmLockDatabaseExclusive();
00982 
00983         /* Get the pointer to the service record */
00984         lpService = hService->ServiceEntry;
00985 
00986         /* FIXME: add handle cleanup code */
00987 
00988         /* Free the handle */
00989         HeapFree(GetProcessHeap(), 0, hService);
00990         hService = NULL;
00991 
00992         ASSERT(lpService->dwRefCount > 0);
00993 
00994         lpService->dwRefCount--;
00995         DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
00996                lpService->dwRefCount);
00997 
00998         if (lpService->dwRefCount == 0)
00999         {
01000             /* If this service has been marked for deletion */
01001             if (lpService->bDeleted)
01002             {
01003                 /* Open the Services Reg key */
01004                 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
01005                                         L"System\\CurrentControlSet\\Services",
01006                                         0,
01007                                         KEY_SET_VALUE | KEY_READ,
01008                                         &hServicesKey);
01009                 if (dwError != ERROR_SUCCESS)
01010                 {
01011                     DPRINT("Failed to open services key\n");
01012                     ScmUnlockDatabase();
01013                     return dwError;
01014                 }
01015 
01016                 /* Call the internal function with NULL, just to get bytes we need */
01017                 Int_EnumDependentServicesW(hServicesKey,
01018                                            lpService,
01019                                            SERVICE_ACTIVE,
01020                                            NULL,
01021                                            &pcbBytesNeeded,
01022                                            &dwServicesReturned);
01023 
01024                 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */
01025                 if (pcbBytesNeeded)
01026                 {
01027                     DPRINT("Deletion failed due to running dependencies.\n");
01028                     RegCloseKey(hServicesKey);
01029                     ScmUnlockDatabase();
01030                     return ERROR_SUCCESS;
01031                 }
01032 
01033                 /* There are no references and no runnning dependencies,
01034                    it is now safe to delete the service */
01035 
01036                 /* Delete the Service Key */
01037                 dwError = RegDeleteKeyW(hServicesKey,
01038                                         lpService->lpServiceName);
01039 
01040                 RegCloseKey(hServicesKey);
01041 
01042                 if (dwError != ERROR_SUCCESS)
01043                 {
01044                     DPRINT("Failed to Delete the Service Registry key\n");
01045                     ScmUnlockDatabase();
01046                     return dwError;
01047                 }
01048 
01049                 /* Delete the Service */
01050                 ScmDeleteServiceRecord(lpService);
01051             }
01052         }
01053 
01054         ScmUnlockDatabase();
01055 
01056         *hSCObject = NULL;
01057 
01058         DPRINT("RCloseServiceHandle() done\n");
01059         return ERROR_SUCCESS;
01060     }
01061 
01062     DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
01063 
01064     return ERROR_INVALID_HANDLE;
01065 }
01066 
01067 
01068 /* Function 1 */
01069 DWORD RControlService(
01070     SC_RPC_HANDLE hService,
01071     DWORD dwControl,
01072     LPSERVICE_STATUS lpServiceStatus)
01073 {
01074     PSERVICE_HANDLE hSvc;
01075     PSERVICE lpService;
01076     ACCESS_MASK DesiredAccess;
01077     DWORD dwError = ERROR_SUCCESS;
01078     DWORD pcbBytesNeeded = 0;
01079     DWORD dwServicesReturned = 0;
01080     DWORD dwControlsAccepted;
01081     DWORD dwCurrentState;
01082     HKEY hServicesKey = NULL;
01083 
01084     DPRINT("RControlService() called\n");
01085 
01086     if (ScmShutdown)
01087         return ERROR_SHUTDOWN_IN_PROGRESS;
01088 
01089     /* Check the service handle */
01090     hSvc = ScmGetServiceFromHandle(hService);
01091     if (hSvc == NULL)
01092     {
01093         DPRINT1("Invalid service handle!\n");
01094         return ERROR_INVALID_HANDLE;
01095     }
01096 
01097     /* Check the service entry point */
01098     lpService = hSvc->ServiceEntry;
01099     if (lpService == NULL)
01100     {
01101         DPRINT1("lpService == NULL!\n");
01102         return ERROR_INVALID_HANDLE;
01103     }
01104 
01105     /* Check access rights */
01106     switch (dwControl)
01107     {
01108         case SERVICE_CONTROL_STOP:
01109             DesiredAccess = SERVICE_STOP;
01110             break;
01111 
01112         case SERVICE_CONTROL_PAUSE:
01113         case SERVICE_CONTROL_CONTINUE:
01114             DesiredAccess = SERVICE_PAUSE_CONTINUE;
01115             break;
01116 
01117         case SERVICE_INTERROGATE:
01118             DesiredAccess = SERVICE_INTERROGATE;
01119             break;
01120 
01121         default:
01122             if (dwControl >= 128 && dwControl <= 255)
01123                 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
01124             else
01125                 return ERROR_INVALID_PARAMETER;
01126             break;
01127     }
01128 
01129     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
01130                                   DesiredAccess))
01131         return ERROR_ACCESS_DENIED;
01132 
01133     /* Return the current service status information */
01134     RtlCopyMemory(lpServiceStatus,
01135                   &lpService->Status,
01136                   sizeof(SERVICE_STATUS));
01137 
01138     if (dwControl == SERVICE_CONTROL_STOP)
01139     {
01140         /* Check if the service has dependencies running as windows
01141            doesn't stop a service that does */
01142 
01143         /* Open the Services Reg key */
01144         dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
01145                                 L"System\\CurrentControlSet\\Services",
01146                                 0,
01147                                 KEY_READ,
01148                                 &hServicesKey);
01149         if (dwError != ERROR_SUCCESS)
01150         {
01151             DPRINT("Failed to open services key\n");
01152             return dwError;
01153         }
01154 
01155         /* Call the internal function with NULL, just to get bytes we need */
01156         Int_EnumDependentServicesW(hServicesKey,
01157                                    lpService,
01158                                    SERVICE_ACTIVE,
01159                                    NULL,
01160                                    &pcbBytesNeeded,
01161                                    &dwServicesReturned);
01162 
01163         RegCloseKey(hServicesKey);
01164 
01165         /* If pcbBytesNeeded is not zero then there are services running that
01166            are dependent on this service */
01167         if (pcbBytesNeeded != 0)
01168         {
01169             DPRINT("Service has running dependencies. Failed to stop service.\n");
01170             return ERROR_DEPENDENT_SERVICES_RUNNING;
01171         }
01172     }
01173 
01174     if (lpService->Status.dwServiceType & SERVICE_DRIVER)
01175     {
01176         /* Send control code to the driver */
01177         dwError = ScmControlDriver(lpService,
01178                                    dwControl,
01179                                    lpServiceStatus);
01180     }
01181     else
01182     {
01183         dwControlsAccepted = lpService->Status.dwControlsAccepted;
01184         dwCurrentState = lpService->Status.dwCurrentState;
01185 
01186         /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
01187         if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
01188             return ERROR_SERVICE_NOT_ACTIVE;
01189 
01190         /* Check the current state before sending a control request */
01191         switch (dwCurrentState)
01192         {
01193             case SERVICE_STOP_PENDING:
01194             case SERVICE_STOPPED:
01195                 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
01196 
01197             case SERVICE_START_PENDING:
01198                 switch (dwControl)
01199                 {
01200                     case SERVICE_CONTROL_STOP:
01201                         break;
01202 
01203                     case SERVICE_CONTROL_INTERROGATE:
01204                         RtlCopyMemory(lpServiceStatus,
01205                                       &lpService->Status,
01206                                       sizeof(SERVICE_STATUS));
01207                         return ERROR_SUCCESS;
01208 
01209                     default:
01210                         return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
01211                 }
01212                 break;
01213         }
01214 
01215         /* Check if the control code is acceptable to the service */
01216         switch (dwControl)
01217         {
01218             case SERVICE_CONTROL_STOP:
01219                 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
01220                     return ERROR_INVALID_SERVICE_CONTROL;
01221                 break;
01222 
01223             case SERVICE_CONTROL_PAUSE:
01224             case SERVICE_CONTROL_CONTINUE:
01225                 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
01226                     return ERROR_INVALID_SERVICE_CONTROL;
01227                 break;
01228         }
01229 
01230         /* Send control code to the service */
01231         dwError = ScmControlService(lpService,
01232                                     dwControl);
01233 
01234         /* Return service status information */
01235         RtlCopyMemory(lpServiceStatus,
01236                       &lpService->Status,
01237                       sizeof(SERVICE_STATUS));
01238     }
01239 
01240     if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
01241         dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
01242 
01243     return dwError;
01244 }
01245 
01246 
01247 /* Function 2 */
01248 DWORD RDeleteService(
01249     SC_RPC_HANDLE hService)
01250 {
01251     PSERVICE_HANDLE hSvc;
01252     PSERVICE lpService;
01253     DWORD dwError;
01254 
01255     DPRINT("RDeleteService() called\n");
01256 
01257     if (ScmShutdown)
01258         return ERROR_SHUTDOWN_IN_PROGRESS;
01259 
01260     hSvc = ScmGetServiceFromHandle(hService);
01261     if (hSvc == NULL)
01262     {
01263         DPRINT1("Invalid service handle!\n");
01264         return ERROR_INVALID_HANDLE;
01265     }
01266 
01267     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
01268                                   DELETE))
01269         return ERROR_ACCESS_DENIED;
01270 
01271     lpService = hSvc->ServiceEntry;
01272     if (lpService == NULL)
01273     {
01274         DPRINT("lpService == NULL!\n");
01275         return ERROR_INVALID_HANDLE;
01276     }
01277 
01278     /* Lock the service database exclusively */
01279     ScmLockDatabaseExclusive();
01280 
01281     if (lpService->bDeleted)
01282     {
01283         DPRINT("The service has already been marked for delete!\n");
01284         dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
01285         goto Done;
01286     }
01287 
01288     /* Mark service for delete */
01289     lpService->bDeleted = TRUE;
01290 
01291     dwError = ScmMarkServiceForDelete(lpService);
01292 
01293 Done:;
01294     /* Unlock the service database */
01295     ScmUnlockDatabase();
01296 
01297     DPRINT("RDeleteService() done\n");
01298 
01299     return dwError;
01300 }
01301 
01302 
01303 /* Function 3 */
01304 DWORD RLockServiceDatabase(
01305     SC_RPC_HANDLE hSCManager,
01306     LPSC_RPC_LOCK lpLock)
01307 {
01308     PMANAGER_HANDLE hMgr;
01309 
01310     DPRINT("RLockServiceDatabase() called\n");
01311 
01312     *lpLock = 0;
01313 
01314     hMgr = ScmGetServiceManagerFromHandle(hSCManager);
01315     if (hMgr == NULL)
01316     {
01317         DPRINT1("Invalid service manager handle!\n");
01318         return ERROR_INVALID_HANDLE;
01319     }
01320 
01321     if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
01322                                   SC_MANAGER_LOCK))
01323         return ERROR_ACCESS_DENIED;
01324 
01325 //    return ScmLockDatabase(0, hMgr->0xC, hLock);
01326 
01327     /* FIXME: Lock the database */
01328     *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */
01329 
01330     return ERROR_SUCCESS;
01331 }
01332 
01333 
01334 /* Function 4 */
01335 DWORD RQueryServiceObjectSecurity(
01336     SC_RPC_HANDLE hService,
01337     SECURITY_INFORMATION dwSecurityInformation,
01338     LPBYTE lpSecurityDescriptor,
01339     DWORD cbBufSize,
01340     LPBOUNDED_DWORD_256K pcbBytesNeeded)
01341 {
01342     PSERVICE_HANDLE hSvc;
01343     PSERVICE lpService;
01344     ULONG DesiredAccess = 0;
01345     NTSTATUS Status;
01346     DWORD dwBytesNeeded;
01347     DWORD dwError;
01348 
01349 
01350     SECURITY_DESCRIPTOR ObjectDescriptor;
01351 
01352     DPRINT("RQueryServiceObjectSecurity() called\n");
01353 
01354     hSvc = ScmGetServiceFromHandle(hService);
01355     if (hSvc == NULL)
01356     {
01357         DPRINT1("Invalid service handle!\n");
01358         return ERROR_INVALID_HANDLE;
01359     }
01360 
01361     if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
01362                                  GROUP_SECURITY_INFORMATION |
01363                                  OWNER_SECURITY_INFORMATION))
01364         DesiredAccess |= READ_CONTROL;
01365 
01366     if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
01367         DesiredAccess |= ACCESS_SYSTEM_SECURITY;
01368 
01369     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
01370                                   DesiredAccess))
01371     {
01372         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
01373         return ERROR_ACCESS_DENIED;
01374     }
01375 
01376     lpService = hSvc->ServiceEntry;
01377     if (lpService == NULL)
01378     {
01379         DPRINT("lpService == NULL!\n");
01380         return ERROR_INVALID_HANDLE;
01381     }
01382 
01383     /* Lock the service database */
01384     ScmLockDatabaseShared();
01385 
01386 
01387     /* hack */
01388     Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
01389 
01390     Status = RtlQuerySecurityObject(&ObjectDescriptor  /* lpService->lpSecurityDescriptor */,
01391                                     dwSecurityInformation,
01392                                     (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
01393                                     cbBufSize,
01394                                     &dwBytesNeeded);
01395 
01396     /* Unlock the service database */
01397     ScmUnlockDatabase();
01398 
01399     if (NT_SUCCESS(Status))
01400     {
01401         *pcbBytesNeeded = dwBytesNeeded;
01402         dwError = STATUS_SUCCESS;
01403     }
01404     else if (Status == STATUS_BUFFER_TOO_SMALL)
01405     {
01406         *pcbBytesNeeded = dwBytesNeeded;
01407         dwError = ERROR_INSUFFICIENT_BUFFER;
01408     }
01409     else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
01410     {
01411         dwError = ERROR_GEN_FAILURE;
01412     }
01413     else
01414     {
01415         dwError = RtlNtStatusToDosError(Status);
01416     }
01417 
01418     return dwError;
01419 }
01420 
01421 
01422 /* Function 5 */
01423 DWORD RSetServiceObjectSecurity(
01424     SC_RPC_HANDLE hService,
01425     DWORD dwSecurityInformation,
01426     LPBYTE lpSecurityDescriptor,
01427     DWORD dwSecuityDescriptorSize)
01428 {
01429     PSERVICE_HANDLE hSvc;
01430     PSERVICE lpService;
01431     ULONG DesiredAccess = 0;
01432     /* HANDLE hToken = NULL; */
01433     HKEY hServiceKey;
01434     /* NTSTATUS Status; */
01435     DWORD dwError;
01436 
01437     DPRINT("RSetServiceObjectSecurity() called\n");
01438 
01439     hSvc = ScmGetServiceFromHandle(hService);
01440     if (hSvc == NULL)
01441     {
01442         DPRINT1("Invalid service handle!\n");
01443         return ERROR_INVALID_HANDLE;
01444     }
01445 
01446     if (dwSecurityInformation == 0 ||
01447         dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
01448         | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
01449         return ERROR_INVALID_PARAMETER;
01450 
01451     if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
01452         return ERROR_INVALID_PARAMETER;
01453 
01454     if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
01455         DesiredAccess |= ACCESS_SYSTEM_SECURITY;
01456 
01457     if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
01458         DesiredAccess |= WRITE_DAC;
01459 
01460     if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
01461         DesiredAccess |= WRITE_OWNER;
01462 
01463     if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
01464         (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
01465         return ERROR_INVALID_PARAMETER;
01466 
01467     if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
01468         (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
01469         return ERROR_INVALID_PARAMETER;
01470 
01471     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
01472                                   DesiredAccess))
01473     {
01474         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
01475         return ERROR_ACCESS_DENIED;
01476     }
01477 
01478     lpService = hSvc->ServiceEntry;
01479     if (lpService == NULL)
01480     {
01481         DPRINT("lpService == NULL!\n");
01482         return ERROR_INVALID_HANDLE;
01483     }
01484 
01485     if (lpService->bDeleted)
01486         return ERROR_SERVICE_MARKED_FOR_DELETE;
01487 
01488 #if 0
01489     RpcImpersonateClient(NULL);
01490 
01491     Status = NtOpenThreadToken(NtCurrentThread(),
01492                                8,
01493                                TRUE,
01494                                &hToken);
01495     if (!NT_SUCCESS(Status))
01496         return RtlNtStatusToDosError(Status);
01497 
01498     RpcRevertToSelf();
01499 #endif
01500 
01501     /* Lock the service database exclusive */
01502     ScmLockDatabaseExclusive();
01503 
01504 #if 0
01505     Status = RtlSetSecurityObject(dwSecurityInformation,
01506                                   (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
01507                                   &lpService->lpSecurityDescriptor,
01508                                   &ScmServiceMapping,
01509                                   hToken);
01510     if (!NT_SUCCESS(Status))
01511     {
01512         dwError = RtlNtStatusToDosError(Status);
01513         goto Done;
01514     }
01515 #endif
01516 
01517     dwError = ScmOpenServiceKey(lpService->lpServiceName,
01518                                 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
01519                                 &hServiceKey);
01520     if (dwError != ERROR_SUCCESS)
01521         goto Done;
01522 
01523     UNIMPLEMENTED;
01524     dwError = ERROR_SUCCESS;
01525 //    dwError = ScmWriteSecurityDescriptor(hServiceKey,
01526 //                                         lpService->lpSecurityDescriptor);
01527 
01528     RegFlushKey(hServiceKey);
01529     RegCloseKey(hServiceKey);
01530 
01531 Done:
01532 
01533 #if 0
01534     if (hToken != NULL)
01535         NtClose(hToken);
01536 #endif
01537 
01538     /* Unlock service database */
01539     ScmUnlockDatabase();
01540 
01541     DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
01542 
01543     return dwError;
01544 }
01545 
01546 
01547 /* Function 6 */
01548 DWORD RQueryServiceStatus(
01549     SC_RPC_HANDLE hService,
01550     LPSERVICE_STATUS lpServiceStatus)
01551 {
01552     PSERVICE_HANDLE hSvc;
01553     PSERVICE lpService;
01554 
01555     DPRINT("RQueryServiceStatus() called\n");
01556 
01557     if (ScmShutdown)
01558         return ERROR_SHUTDOWN_IN_PROGRESS;
01559 
01560     hSvc = ScmGetServiceFromHandle(hService);
01561     if (hSvc == NULL)
01562     {
01563         DPRINT1("Invalid service handle!\n");
01564         return ERROR_INVALID_HANDLE;
01565     }
01566 
01567     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
01568                                   SERVICE_QUERY_STATUS))
01569     {
01570         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
01571         return ERROR_ACCESS_DENIED;
01572     }
01573 
01574     lpService = hSvc->ServiceEntry;
01575     if (lpService == NULL)
01576     {
01577         DPRINT("lpService == NULL!\n");
01578         return ERROR_INVALID_HANDLE;
01579     }
01580 
01581     /* Lock the service database shared */
01582     ScmLockDatabaseShared();
01583 
01584     /* Return service status information */
01585     RtlCopyMemory(lpServiceStatus,
01586                   &lpService->Status,
01587                   sizeof(SERVICE_STATUS));
01588 
01589     /* Unlock the service database */
01590     ScmUnlockDatabase();
01591 
01592     return ERROR_SUCCESS;
01593 }
01594 
01595 
01596 static BOOL
01597 ScmIsValidServiceState(DWORD dwCurrentState)
01598 {
01599     switch (dwCurrentState)
01600     {
01601         case SERVICE_STOPPED:
01602         case SERVICE_START_PENDING:
01603         case SERVICE_STOP_PENDING:
01604         case SERVICE_RUNNING:
01605         case SERVICE_CONTINUE_PENDING:
01606         case SERVICE_PAUSE_PENDING:
01607         case SERVICE_PAUSED:
01608             return TRUE;
01609 
01610         default:
01611             return FALSE;
01612     }
01613 }
01614 
01615 
01616 /* Function 7 */
01617 DWORD RSetServiceStatus(
01618     RPC_SERVICE_STATUS_HANDLE hServiceStatus,
01619     LPSERVICE_STATUS lpServiceStatus)
01620 {
01621     PSERVICE lpService;
01622     DWORD dwPreviousState;
01623     LPCWSTR lpErrorStrings[2];
01624     WCHAR szErrorBuffer[32];
01625 
01626     DPRINT("RSetServiceStatus() called\n");
01627     DPRINT("hServiceStatus = %p\n", hServiceStatus);
01628     DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
01629     DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
01630     DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
01631     DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
01632     DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
01633     DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
01634     DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
01635 
01636     if (hServiceStatus == 0)
01637     {
01638         DPRINT("hServiceStatus == NULL!\n");
01639         return ERROR_INVALID_HANDLE;
01640     }
01641 
01642     lpService = (PSERVICE)hServiceStatus;
01643     if (lpService == NULL)
01644     {
01645         DPRINT("lpService == NULL!\n");
01646         return ERROR_INVALID_HANDLE;
01647     }
01648 
01649     /* Check current state */
01650     if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
01651     {
01652         DPRINT("Invalid service state!\n");
01653         return ERROR_INVALID_DATA;
01654     }
01655 
01656     /* Check service type */
01657     if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
01658          (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
01659     {
01660         DPRINT("Invalid service type!\n");
01661         return ERROR_INVALID_DATA;
01662     }
01663 
01664     /* Check accepted controls */
01665     if (lpServiceStatus->dwControlsAccepted & ~0xFF)
01666     {
01667         DPRINT("Invalid controls accepted!\n");
01668         return ERROR_INVALID_DATA;
01669     }
01670 
01671     /* Lock the service database exclusively */
01672     ScmLockDatabaseExclusive();
01673 
01674     /* Save the current service state */
01675     dwPreviousState = lpService->Status.dwCurrentState;
01676 
01677     RtlCopyMemory(&lpService->Status,
01678                   lpServiceStatus,
01679                   sizeof(SERVICE_STATUS));
01680 
01681     /* Unlock the service database */
01682     ScmUnlockDatabase();
01683 
01684     /* Log a failed service stop */
01685     if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
01686         (dwPreviousState != SERVICE_STOPPED))
01687     {
01688         if (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS)
01689         {
01690             swprintf(szErrorBuffer, L"%lu", lpServiceStatus->dwWin32ExitCode);
01691             lpErrorStrings[0] = lpService->lpDisplayName;
01692             lpErrorStrings[1] = szErrorBuffer;
01693 
01694             ScmLogError(EVENT_SERVICE_EXIT_FAILED,
01695                         2,
01696                         lpErrorStrings);
01697         }
01698     }
01699 
01700     DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
01701     DPRINT("RSetServiceStatus() done\n");
01702 
01703     return ERROR_SUCCESS;
01704 }
01705 
01706 
01707 /* Function 8 */
01708 DWORD RUnlockServiceDatabase(
01709     LPSC_RPC_LOCK Lock)
01710 {
01711     UNIMPLEMENTED;
01712     return ERROR_SUCCESS;
01713 }
01714 
01715 
01716 /* Function 9 */
01717 DWORD RNotifyBootConfigStatus(
01718     SVCCTL_HANDLEW lpMachineName,
01719     DWORD BootAcceptable)
01720 {
01721     DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
01722     return ERROR_SUCCESS;
01723 
01724 //    UNIMPLEMENTED;
01725 //    return ERROR_CALL_NOT_IMPLEMENTED;
01726 }
01727 
01728 
01729 /* Function 10 */
01730 DWORD RI_ScSetServiceBitsW(
01731     RPC_SERVICE_STATUS_HANDLE hServiceStatus,
01732     DWORD dwServiceBits,
01733     int bSetBitsOn,
01734     int bUpdateImmediately,
01735     wchar_t *lpString)
01736 {
01737     UNIMPLEMENTED;
01738     return ERROR_CALL_NOT_IMPLEMENTED;
01739 }
01740 
01741 
01742 /* Function 11 */
01743 DWORD RChangeServiceConfigW(
01744     SC_RPC_HANDLE hService,
01745     DWORD dwServiceType,
01746     DWORD dwStartType,
01747     DWORD dwErrorControl,
01748     LPWSTR lpBinaryPathName,
01749     LPWSTR lpLoadOrderGroup,
01750     LPDWORD lpdwTagId,
01751     LPBYTE lpDependencies,
01752     DWORD dwDependSize,
01753     LPWSTR lpServiceStartName,
01754     LPBYTE lpPassword,
01755     DWORD dwPwSize,
01756     LPWSTR lpDisplayName)
01757 {
01758     DWORD dwError = ERROR_SUCCESS;
01759     PSERVICE_HANDLE hSvc;
01760     PSERVICE lpService = NULL;
01761     HKEY hServiceKey = NULL;
01762     LPWSTR lpDisplayNameW = NULL;
01763     LPWSTR lpImagePathW = NULL;
01764 
01765     DPRINT("RChangeServiceConfigW() called\n");
01766     DPRINT("dwServiceType = %lu\n", dwServiceType);
01767     DPRINT("dwStartType = %lu\n", dwStartType);
01768     DPRINT("dwErrorControl = %lu\n", dwErrorControl);
01769     DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
01770     DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
01771     DPRINT("lpDisplayName = %S\n", lpDisplayName);
01772 
01773     if (ScmShutdown)
01774         return ERROR_SHUTDOWN_IN_PROGRESS;
01775 
01776     hSvc = ScmGetServiceFromHandle(hService);
01777     if (hSvc == NULL)
01778     {
01779         DPRINT1("Invalid service handle!\n");
01780         return ERROR_INVALID_HANDLE;
01781     }
01782 
01783     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
01784                                   SERVICE_CHANGE_CONFIG))
01785     {
01786         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
01787         return ERROR_ACCESS_DENIED;
01788     }
01789 
01790     lpService = hSvc->ServiceEntry;
01791     if (lpService == NULL)
01792     {
01793         DPRINT("lpService == NULL!\n");
01794         return ERROR_INVALID_HANDLE;
01795     }
01796 
01797     /* Lock the service database exclusively */
01798     ScmLockDatabaseExclusive();
01799 
01800     if (lpService->bDeleted)
01801     {
01802         DPRINT("The service has already been marked for delete!\n");
01803         dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
01804         goto done;
01805     }
01806 
01807     /* Open the service key */
01808     dwError = ScmOpenServiceKey(lpService->szServiceName,
01809                                 KEY_SET_VALUE,
01810                                 &hServiceKey);
01811     if (dwError != ERROR_SUCCESS)
01812         goto done;
01813 
01814     /* Write service data to the registry */
01815     /* Set the display name */
01816     if (lpDisplayName != NULL && *lpDisplayName != 0)
01817     {
01818         RegSetValueExW(hServiceKey,
01819                        L"DisplayName",
01820                        0,
01821                        REG_SZ,
01822                        (LPBYTE)lpDisplayName,
01823                        (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
01824 
01825         /* Update the display name */
01826         lpDisplayNameW = HeapAlloc(GetProcessHeap(),
01827                                    0,
01828                                    (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
01829         if (lpDisplayNameW == NULL)
01830         {
01831             dwError = ERROR_NOT_ENOUGH_MEMORY;
01832             goto done;
01833         }
01834 
01835         if (lpService->lpDisplayName != lpService->lpServiceName)
01836             HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
01837 
01838         lpService->lpDisplayName = lpDisplayNameW;
01839     }
01840 
01841     if (dwServiceType != SERVICE_NO_CHANGE)
01842     {
01843         /* Set the service type */
01844         dwError = RegSetValueExW(hServiceKey,
01845                                  L"Type",
01846                                  0,
01847                                  REG_DWORD,
01848                                  (LPBYTE)&dwServiceType,
01849                                  sizeof(DWORD));
01850         if (dwError != ERROR_SUCCESS)
01851             goto done;
01852 
01853         lpService->Status.dwServiceType = dwServiceType;
01854     }
01855 
01856     if (dwStartType != SERVICE_NO_CHANGE)
01857     {
01858         /* Set the start value */
01859         dwError = RegSetValueExW(hServiceKey,
01860                                  L"Start",
01861                                  0,
01862                                  REG_DWORD,
01863                                  (LPBYTE)&dwStartType,
01864                                  sizeof(DWORD));
01865         if (dwError != ERROR_SUCCESS)
01866             goto done;
01867 
01868         lpService->dwStartType = dwStartType;
01869     }
01870 
01871     if (dwErrorControl != SERVICE_NO_CHANGE)
01872     {
01873         /* Set the error control value */
01874         dwError = RegSetValueExW(hServiceKey,
01875                                  L"ErrorControl",
01876                                  0,
01877                                  REG_DWORD,
01878                                  (LPBYTE)&dwErrorControl,
01879                                  sizeof(DWORD));
01880         if (dwError != ERROR_SUCCESS)
01881             goto done;
01882 
01883         lpService->dwErrorControl = dwErrorControl;
01884     }
01885 
01886     if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
01887     {
01888         /* Set the image path */
01889         lpImagePathW = lpBinaryPathName;
01890 
01891         if (lpService->Status.dwServiceType & SERVICE_DRIVER)
01892         {
01893             dwError = ScmCanonDriverImagePath(lpService->dwStartType,
01894                                               lpBinaryPathName,
01895                                               &lpImagePathW);
01896 
01897             if (dwError != ERROR_SUCCESS)
01898                 goto done;
01899         }
01900 
01901         dwError = RegSetValueExW(hServiceKey,
01902                                  L"ImagePath",
01903                                  0,
01904                                  REG_EXPAND_SZ,
01905                                  (LPBYTE)lpImagePathW,
01906                                  (wcslen(lpImagePathW) + 1) * sizeof(WCHAR));
01907 
01908         if (lpImagePathW != lpBinaryPathName)
01909             HeapFree(GetProcessHeap(), 0, lpImagePathW);
01910 
01911         if (dwError != ERROR_SUCCESS)
01912             goto done;
01913     }
01914 
01915     /* Set the group name */
01916     if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
01917     {
01918         dwError = RegSetValueExW(hServiceKey,
01919                                  L"Group",
01920                                  0,
01921                                  REG_SZ,
01922                                  (LPBYTE)lpLoadOrderGroup,
01923                                  (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
01924         if (dwError != ERROR_SUCCESS)
01925             goto done;
01926 
01927         dwError = ScmSetServiceGroup(lpService,
01928                                      lpLoadOrderGroup);
01929         if (dwError != ERROR_SUCCESS)
01930             goto done;
01931     }
01932 
01933     if (lpdwTagId != NULL)
01934     {
01935         dwError = ScmAssignNewTag(lpService);
01936         if (dwError != ERROR_SUCCESS)
01937             goto done;
01938 
01939         dwError = RegSetValueExW(hServiceKey,
01940                                  L"Tag",
01941                                  0,
01942                                  REG_DWORD,
01943                                  (LPBYTE)&lpService->dwTag,
01944                                  sizeof(DWORD));
01945         if (dwError != ERROR_SUCCESS)
01946             goto done;
01947 
01948         *lpdwTagId = lpService->dwTag;
01949     }
01950 
01951     /* Write dependencies */
01952     if (lpDependencies != NULL && *lpDependencies != 0)
01953     {
01954         dwError = ScmWriteDependencies(hServiceKey,
01955                                        (LPWSTR)lpDependencies,
01956                                        dwDependSize);
01957         if (dwError != ERROR_SUCCESS)
01958             goto done;
01959     }
01960 
01961     if (lpPassword != NULL)
01962     {
01963         /* FIXME: Write password */
01964     }
01965 
01966 done:
01967     if (hServiceKey != NULL)
01968         RegCloseKey(hServiceKey);
01969 
01970     /* Unlock the service database */
01971     ScmUnlockDatabase();
01972 
01973     DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
01974 
01975     return dwError;
01976 }
01977 
01978 
01979 /* Function 12 */
01980 DWORD RCreateServiceW(
01981     SC_RPC_HANDLE hSCManager,
01982     LPCWSTR lpServiceName,
01983     LPCWSTR lpDisplayName,
01984     DWORD dwDesiredAccess,
01985     DWORD dwServiceType,
01986     DWORD dwStartType,
01987     DWORD dwErrorControl,
01988     LPCWSTR lpBinaryPathName,
01989     LPCWSTR lpLoadOrderGroup,
01990     LPDWORD lpdwTagId,
01991     LPBYTE lpDependencies,
01992     DWORD dwDependSize,
01993     LPCWSTR lpServiceStartName,
01994     LPBYTE lpPassword,
01995     DWORD dwPwSize,
01996     LPSC_RPC_HANDLE lpServiceHandle)
01997 {
01998     PMANAGER_HANDLE hManager;
01999     DWORD dwError = ERROR_SUCCESS;
02000     PSERVICE lpService = NULL;
02001     SC_HANDLE hServiceHandle = NULL;
02002     LPWSTR lpImagePath = NULL;
02003     HKEY hServiceKey = NULL;
02004     LPWSTR lpObjectName;
02005 
02006     DPRINT("RCreateServiceW() called\n");
02007     DPRINT("lpServiceName = %S\n", lpServiceName);
02008     DPRINT("lpDisplayName = %S\n", lpDisplayName);
02009     DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
02010     DPRINT("dwServiceType = %lu\n", dwServiceType);
02011     DPRINT("dwStartType = %lu\n", dwStartType);
02012     DPRINT("dwErrorControl = %lu\n", dwErrorControl);
02013     DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
02014     DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
02015     DPRINT("lpdwTagId = %p\n", lpdwTagId);
02016 
02017     if (ScmShutdown)
02018         return ERROR_SHUTDOWN_IN_PROGRESS;
02019 
02020     hManager = ScmGetServiceManagerFromHandle(hSCManager);
02021     if (hManager == NULL)
02022     {
02023         DPRINT1("Invalid service manager handle!\n");
02024         return ERROR_INVALID_HANDLE;
02025     }
02026 
02027     /* Check access rights */
02028     if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
02029                                   SC_MANAGER_CREATE_SERVICE))
02030     {
02031         DPRINT("Insufficient access rights! 0x%lx\n",
02032                hManager->Handle.DesiredAccess);
02033         return ERROR_ACCESS_DENIED;
02034     }
02035 
02036     if (wcslen(lpServiceName) == 0)
02037     {
02038         return ERROR_INVALID_NAME;
02039     }
02040 
02041     if (wcslen(lpBinaryPathName) == 0)
02042     {
02043         return ERROR_INVALID_PARAMETER;
02044     }
02045 
02046     /* Check for invalid service type value */
02047     if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
02048         (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
02049         ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
02050         ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
02051             return ERROR_INVALID_PARAMETER;
02052 
02053     /* Check for invalid start type value */
02054     if ((dwStartType != SERVICE_BOOT_START) &&
02055         (dwStartType != SERVICE_SYSTEM_START) &&
02056         (dwStartType != SERVICE_AUTO_START) &&
02057         (dwStartType != SERVICE_DEMAND_START) &&
02058         (dwStartType != SERVICE_DISABLED))
02059         return ERROR_INVALID_PARAMETER;
02060 
02061     /* Only drivers can be boot start or system start services */
02062     if ((dwStartType == SERVICE_BOOT_START) ||
02063         (dwStartType == SERVICE_SYSTEM_START))
02064     {
02065         if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
02066             (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
02067             return ERROR_INVALID_PARAMETER;
02068     }
02069 
02070     /* Check for invalid error control value */
02071     if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
02072         (dwErrorControl != SERVICE_ERROR_NORMAL) &&
02073         (dwErrorControl != SERVICE_ERROR_SEVERE) &&
02074         (dwErrorControl != SERVICE_ERROR_CRITICAL))
02075         return ERROR_INVALID_PARAMETER;
02076 
02077     if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
02078         (lpServiceStartName))
02079     {
02080         return ERROR_INVALID_PARAMETER;
02081     }
02082 
02083     if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
02084     {
02085         return ERROR_INVALID_PARAMETER;
02086     }
02087 
02088     /* Lock the service database exclusively */
02089     ScmLockDatabaseExclusive();
02090 
02091     lpService = ScmGetServiceEntryByName(lpServiceName);
02092     if (lpService)
02093     {
02094         /* Unlock the service database */
02095         ScmUnlockDatabase();
02096 
02097         /* Check if it is marked for deletion */
02098         if (lpService->bDeleted)
02099             return ERROR_SERVICE_MARKED_FOR_DELETE;
02100 
02101         /* Return Error exist */
02102         return ERROR_SERVICE_EXISTS;
02103     }
02104 
02105     if (lpDisplayName != NULL &&
02106         ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
02107     {
02108         /* Unlock the service database */
02109         ScmUnlockDatabase();
02110 
02111         return ERROR_DUPLICATE_SERVICE_NAME;
02112     }
02113 
02114     if (dwServiceType & SERVICE_DRIVER)
02115     {
02116         dwError = ScmCanonDriverImagePath(dwStartType,
02117                                           lpBinaryPathName,
02118                                           &lpImagePath);
02119         if (dwError != ERROR_SUCCESS)
02120             goto done;
02121     }
02122     else
02123     {
02124         if (dwStartType == SERVICE_BOOT_START ||
02125             dwStartType == SERVICE_SYSTEM_START)
02126         {
02127             /* Unlock the service database */
02128             ScmUnlockDatabase();
02129 
02130             return ERROR_INVALID_PARAMETER;
02131         }
02132     }
02133 
02134     /* Allocate a new service entry */
02135     dwError = ScmCreateNewServiceRecord(lpServiceName,
02136                                         &lpService);
02137     if (dwError != ERROR_SUCCESS)
02138         goto done;
02139 
02140     /* Fill the new service entry */
02141     lpService->Status.dwServiceType = dwServiceType;
02142     lpService->dwStartType = dwStartType;
02143     lpService->dwErrorControl = dwErrorControl;
02144 
02145     /* Fill the display name */
02146     if (lpDisplayName != NULL &&
02147         *lpDisplayName != 0 &&
02148         _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
02149     {
02150         lpService->lpDisplayName = HeapAlloc(GetProcessHeap(), 0,
02151                                              (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
02152         if (lpService->lpDisplayName == NULL)
02153         {
02154             dwError = ERROR_NOT_ENOUGH_MEMORY;
02155             goto done;
02156         }
02157         wcscpy(lpService->lpDisplayName, lpDisplayName);
02158     }
02159 
02160     /* Assign the service to a group */
02161     if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
02162     {
02163         dwError = ScmSetServiceGroup(lpService,
02164                                      lpLoadOrderGroup);
02165         if (dwError != ERROR_SUCCESS)
02166             goto done;
02167     }
02168 
02169     /* Assign a new tag */
02170     if (lpdwTagId != NULL)
02171     {
02172         dwError = ScmAssignNewTag(lpService);
02173         if (dwError != ERROR_SUCCESS)
02174             goto done;
02175     }
02176 
02177     /* Write service data to the registry */
02178     /* Create the service key */
02179     dwError = ScmCreateServiceKey(lpServiceName,
02180                                   KEY_WRITE,
02181                                   &hServiceKey);
02182     if (dwError != ERROR_SUCCESS)
02183         goto done;
02184 
02185     /* Set the display name */
02186     if (lpDisplayName != NULL && *lpDisplayName != 0)
02187     {
02188         RegSetValueExW(hServiceKey,
02189                        L"DisplayName",
02190                        0,
02191                        REG_SZ,
02192                        (LPBYTE)lpDisplayName,
02193                        (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
02194     }
02195 
02196     /* Set the service type */
02197     dwError = RegSetValueExW(hServiceKey,
02198                              L"Type",
02199                              0,
02200                              REG_DWORD,
02201                              (LPBYTE)&dwServiceType,
02202                              sizeof(DWORD));
02203     if (dwError != ERROR_SUCCESS)
02204         goto done;
02205 
02206     /* Set the start value */
02207     dwError = RegSetValueExW(hServiceKey,
02208                              L"Start",
02209                              0,
02210                              REG_DWORD,
02211                              (LPBYTE)&dwStartType,
02212                              sizeof(DWORD));
02213     if (dwError != ERROR_SUCCESS)
02214         goto done;
02215 
02216     /* Set the error control value */
02217     dwError = RegSetValueExW(hServiceKey,
02218                              L"ErrorControl",
02219                              0,
02220                              REG_DWORD,
02221                              (LPBYTE)&dwErrorControl,
02222                              sizeof(DWORD));
02223     if (dwError != ERROR_SUCCESS)
02224         goto done;
02225 
02226     /* Set the image path */
02227     if (dwServiceType & SERVICE_WIN32)
02228     {
02229         dwError = RegSetValueExW(hServiceKey,
02230                                  L"ImagePath",
02231                                  0,
02232                                  REG_EXPAND_SZ,
02233                                  (LPBYTE)lpBinaryPathName,
02234                                  (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
02235         if (dwError != ERROR_SUCCESS)
02236             goto done;
02237     }
02238     else if (dwServiceType & SERVICE_DRIVER)
02239     {
02240         dwError = RegSetValueExW(hServiceKey,
02241                                  L"ImagePath",
02242                                  0,
02243                                  REG_EXPAND_SZ,
02244                                  (LPBYTE)lpImagePath,
02245                                  (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
02246         if (dwError != ERROR_SUCCESS)
02247             goto done;
02248     }
02249 
02250     /* Set the group name */
02251     if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
02252     {
02253         dwError = RegSetValueExW(hServiceKey,
02254                                  L"Group",
02255                                  0,
02256                                  REG_SZ,
02257                                  (LPBYTE)lpLoadOrderGroup,
02258                                  (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
02259         if (dwError != ERROR_SUCCESS)
02260             goto done;
02261     }
02262 
02263     if (lpdwTagId != NULL)
02264     {
02265         dwError = RegSetValueExW(hServiceKey,
02266                                  L"Tag",
02267                                  0,
02268                                  REG_DWORD,
02269                                  (LPBYTE)&lpService->dwTag,
02270                                  sizeof(DWORD));
02271         if (dwError != ERROR_SUCCESS)
02272             goto done;
02273     }
02274 
02275     /* Write dependencies */
02276     if (lpDependencies != NULL && *lpDependencies != 0)
02277     {
02278         dwError = ScmWriteDependencies(hServiceKey,
02279                                        (LPCWSTR)lpDependencies,
02280                                        dwDependSize);
02281         if (dwError != ERROR_SUCCESS)
02282             goto done;
02283     }
02284 
02285     /* Write service start name */
02286     if (dwServiceType & SERVICE_WIN32)
02287     {
02288         lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
02289         dwError = RegSetValueExW(hServiceKey,
02290                                  L"ObjectName",
02291                                  0,
02292                                  REG_SZ,
02293                                  (LPBYTE)lpObjectName,
02294                                  (wcslen(lpObjectName) + 1) * sizeof(WCHAR));
02295         if (dwError != ERROR_SUCCESS)
02296             goto done;
02297     }
02298 
02299     if (lpPassword != NULL)
02300     {
02301         /* FIXME: Write password */
02302     }
02303 
02304     dwError = ScmCreateServiceHandle(lpService,
02305                                      &hServiceHandle);
02306     if (dwError != ERROR_SUCCESS)
02307         goto done;
02308 
02309     dwError = ScmCheckAccess(hServiceHandle,
02310                              dwDesiredAccess);
02311     if (dwError != ERROR_SUCCESS)
02312         goto done;
02313 
02314     lpService->dwRefCount = 1;
02315     DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
02316 
02317 done:;
02318     /* Unlock the service database */
02319     ScmUnlockDatabase();
02320 
02321     if (hServiceKey != NULL)
02322         RegCloseKey(hServiceKey);
02323 
02324     if (dwError == ERROR_SUCCESS)
02325     {
02326         DPRINT("hService %p\n", hServiceHandle);
02327         *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
02328 
02329         if (lpdwTagId != NULL)
02330             *lpdwTagId = lpService->dwTag;
02331     }
02332     else
02333     {
02334         if (lpService != NULL &&
02335             lpService->lpServiceName != NULL)
02336         {
02337             /* Release the display name buffer */
02338             HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
02339         }
02340 
02341         if (hServiceHandle)
02342         {
02343             /* Remove the service handle */
02344             HeapFree(GetProcessHeap(), 0, hServiceHandle);
02345         }
02346 
02347         if (lpService != NULL)
02348         {
02349             /* FIXME: remove the service entry */
02350         }
02351     }
02352 
02353     if (lpImagePath != NULL)
02354         HeapFree(GetProcessHeap(), 0, lpImagePath);
02355 
02356     DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
02357 
02358     return dwError;
02359 }
02360 
02361 
02362 /* Function 13 */
02363 DWORD REnumDependentServicesW(
02364     SC_RPC_HANDLE hService,
02365     DWORD dwServiceState,
02366     LPBYTE lpServices,
02367     DWORD cbBufSize,
02368     LPBOUNDED_DWORD_256K pcbBytesNeeded,
02369     LPBOUNDED_DWORD_256K lpServicesReturned)
02370 {
02371     DWORD dwError = ERROR_SUCCESS;
02372     DWORD dwServicesReturned = 0;
02373     DWORD dwServiceCount;
02374     HKEY hServicesKey = NULL;
02375     PSERVICE_HANDLE hSvc;
02376     PSERVICE lpService = NULL;
02377     PSERVICE *lpServicesArray = NULL;
02378     LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
02379     LPWSTR lpStr;
02380 
02381     *pcbBytesNeeded = 0;
02382     *lpServicesReturned = 0;
02383 
02384     DPRINT("REnumDependentServicesW() called\n");
02385 
02386     hSvc = ScmGetServiceFromHandle(hService);
02387     if (hSvc == NULL)
02388     {
02389         DPRINT1("Invalid service handle!\n");
02390         return ERROR_INVALID_HANDLE;
02391     }
02392 
02393     lpService = hSvc->ServiceEntry;
02394 
02395     /* Check access rights */
02396     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
02397                                   SC_MANAGER_ENUMERATE_SERVICE))
02398     {
02399         DPRINT("Insufficient access rights! 0x%lx\n",
02400                hSvc->Handle.DesiredAccess);
02401         return ERROR_ACCESS_DENIED;
02402     }
02403 
02404     /* Open the Services Reg key */
02405     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
02406                             L"System\\CurrentControlSet\\Services",
02407                             0,
02408                             KEY_READ,
02409                             &hServicesKey);
02410     if (dwError != ERROR_SUCCESS)
02411         return dwError;
02412 
02413     /* First determine the bytes needed and get the number of dependent services */
02414     dwError = Int_EnumDependentServicesW(hServicesKey,
02415                                          lpService,
02416                                          dwServiceState,
02417                                          NULL,
02418                                          pcbBytesNeeded,
02419                                          &dwServicesReturned);
02420     if (dwError != ERROR_SUCCESS)
02421         goto Done;
02422 
02423     /* If buffer size is less than the bytes needed or pointer is null */
02424     if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
02425     {
02426         dwError = ERROR_MORE_DATA;
02427         goto Done;
02428     }
02429 
02430     /* Allocate memory for array of service pointers */
02431     lpServicesArray = HeapAlloc(GetProcessHeap(),
02432                                 0,
02433                                 (dwServicesReturned + 1) * sizeof(PSERVICE));
02434     if (!lpServicesArray)
02435     {
02436         DPRINT1("Could not allocate a buffer!!\n");
02437         dwError = ERROR_NOT_ENOUGH_MEMORY;
02438         goto Done;
02439     }
02440 
02441     dwServicesReturned = 0;
02442     *pcbBytesNeeded = 0;
02443 
02444     dwError = Int_EnumDependentServicesW(hServicesKey,
02445                                          lpService,
02446                                          dwServiceState,
02447                                          lpServicesArray,
02448                                          pcbBytesNeeded,
02449                                          &dwServicesReturned);
02450     if (dwError != ERROR_SUCCESS)
02451     {
02452         goto Done;
02453     }
02454 
02455     lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
02456     lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
02457 
02458     /* Copy EnumDepenedentService to Buffer */
02459     for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
02460     {
02461         lpService = lpServicesArray[dwServiceCount];
02462 
02463         /* Copy status info */
02464         memcpy(&lpServicesPtr->ServiceStatus,
02465                &lpService->Status,
02466                sizeof(SERVICE_STATUS));
02467 
02468         /* Copy display name */
02469         wcscpy(lpStr, lpService->lpDisplayName);
02470         lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
02471         lpStr += (wcslen(lpService->lpDisplayName) + 1);
02472 
02473         /* Copy service name */
02474         wcscpy(lpStr, lpService->lpServiceName);
02475         lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
02476         lpStr += (wcslen(lpService->lpServiceName) + 1);
02477 
02478         lpServicesPtr ++;
02479     }
02480 
02481     *lpServicesReturned = dwServicesReturned;
02482 
02483 Done:
02484     if (lpServicesArray != NULL)
02485         HeapFree(GetProcessHeap(), 0, lpServicesArray);
02486 
02487     RegCloseKey(hServicesKey);
02488 
02489     DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
02490 
02491     return dwError;
02492 }
02493 
02494 
02495 /* Function 14 */
02496 DWORD REnumServicesStatusW(
02497     SC_RPC_HANDLE hSCManager,
02498     DWORD dwServiceType,
02499     DWORD dwServiceState,
02500     LPBYTE lpBuffer,
02501     DWORD dwBufSize,
02502     LPBOUNDED_DWORD_256K pcbBytesNeeded,
02503     LPBOUNDED_DWORD_256K lpServicesReturned,
02504     LPBOUNDED_DWORD_256K lpResumeHandle)
02505 {
02506     PMANAGER_HANDLE hManager;
02507     PSERVICE lpService;
02508     DWORD dwError = ERROR_SUCCESS;
02509     PLIST_ENTRY ServiceEntry;
02510     PSERVICE CurrentService;
02511     DWORD dwState;
02512     DWORD dwRequiredSize;
02513     DWORD dwServiceCount;
02514     DWORD dwSize;
02515     DWORD dwLastResumeCount = 0;
02516     LPENUM_SERVICE_STATUSW lpStatusPtr;
02517     LPWSTR lpStringPtr;
02518 
02519     DPRINT("REnumServicesStatusW() called\n");
02520 
02521     if (ScmShutdown)
02522         return ERROR_SHUTDOWN_IN_PROGRESS;
02523 
02524     hManager = ScmGetServiceManagerFromHandle(hSCManager);
02525     if (hManager == NULL)
02526     {
02527         DPRINT1("Invalid service manager handle!\n");
02528         return ERROR_INVALID_HANDLE;
02529     }
02530 
02531 
02532     *pcbBytesNeeded = 0;
02533     *lpServicesReturned = 0;
02534 
02535     if ((dwServiceType == 0) ||
02536         ((dwServiceType & ~(SERVICE_DRIVER | SERVICE_WIN32)) != 0))
02537     {
02538         DPRINT("Not a valid Service Type!\n");
02539         return ERROR_INVALID_PARAMETER;
02540     }
02541 
02542     if ((dwServiceState != SERVICE_ACTIVE) &&
02543         (dwServiceState != SERVICE_INACTIVE) &&
02544         (dwServiceState != SERVICE_STATE_ALL))
02545     {
02546         DPRINT("Not a valid Service State!\n");
02547         return ERROR_INVALID_PARAMETER;
02548     }
02549 
02550     /* Check access rights */
02551     if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
02552                                   SC_MANAGER_ENUMERATE_SERVICE))
02553     {
02554         DPRINT("Insufficient access rights! 0x%lx\n",
02555                 hManager->Handle.DesiredAccess);
02556         return ERROR_ACCESS_DENIED;
02557     }
02558 
02559     if (lpResumeHandle)
02560         dwLastResumeCount = *lpResumeHandle;
02561 
02562     /* Lock the service database shared */
02563     ScmLockDatabaseShared();
02564 
02565     lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
02566     if (lpService == NULL)
02567     {
02568         dwError = ERROR_SUCCESS;
02569         goto Done;
02570     }
02571 
02572     dwRequiredSize = 0;
02573     dwServiceCount = 0;
02574 
02575     for (ServiceEntry = &lpService->ServiceListEntry;
02576          ServiceEntry != &ServiceListHead;
02577          ServiceEntry = ServiceEntry->Flink)
02578     {
02579         CurrentService = CONTAINING_RECORD(ServiceEntry,
02580                                            SERVICE,
02581                                            ServiceListEntry);
02582 
02583         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
02584             continue;
02585 
02586         dwState = SERVICE_ACTIVE;
02587         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
02588             dwState = SERVICE_INACTIVE;
02589 
02590         if ((dwState & dwServiceState) == 0)
02591             continue;
02592 
02593         dwSize = sizeof(ENUM_SERVICE_STATUSW) +
02594                  ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
02595                  ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
02596 
02597         if (dwRequiredSize + dwSize > dwBufSize)
02598         {
02599             DPRINT("Service name: %S  no fit\n", CurrentService->lpServiceName);
02600             break;
02601         }
02602 
02603         DPRINT("Service name: %S  fit\n", CurrentService->lpServiceName);
02604         dwRequiredSize += dwSize;
02605         dwServiceCount++;
02606         dwLastResumeCount = CurrentService->dwResumeCount;
02607     }
02608 
02609     DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
02610     DPRINT("dwServiceCount: %lu\n", dwServiceCount);
02611 
02612     for (;
02613          ServiceEntry != &ServiceListHead;
02614          ServiceEntry = ServiceEntry->Flink)
02615     {
02616         CurrentService = CONTAINING_RECORD(ServiceEntry,
02617                                            SERVICE,
02618                                            ServiceListEntry);
02619 
02620         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
02621             continue;
02622 
02623         dwState = SERVICE_ACTIVE;
02624         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
02625             dwState = SERVICE_INACTIVE;
02626 
02627         if ((dwState & dwServiceState) == 0)
02628             continue;
02629 
02630         dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
02631                            ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
02632                            ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
02633 
02634         dwError = ERROR_MORE_DATA;
02635     }
02636 
02637     DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
02638 
02639     if (lpResumeHandle)
02640         *lpResumeHandle = dwLastResumeCount;
02641 
02642     *lpServicesReturned = dwServiceCount;
02643     *pcbBytesNeeded = dwRequiredSize;
02644 
02645     lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
02646     lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
02647                            dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
02648 
02649     dwRequiredSize = 0;
02650     for (ServiceEntry = &lpService->ServiceListEntry;
02651          ServiceEntry != &ServiceListHead;
02652          ServiceEntry = ServiceEntry->Flink)
02653     {
02654         CurrentService = CONTAINING_RECORD(ServiceEntry,
02655                                            SERVICE,
02656                                            ServiceListEntry);
02657 
02658         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
02659             continue;
02660 
02661         dwState = SERVICE_ACTIVE;
02662         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
02663             dwState = SERVICE_INACTIVE;
02664 
02665         if ((dwState & dwServiceState) == 0)
02666             continue;
02667 
02668         dwSize = sizeof(ENUM_SERVICE_STATUSW) +
02669                  ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
02670                  ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
02671 
02672         if (dwRequiredSize + dwSize > dwBufSize)
02673             break;
02674 
02675         /* Copy the service name */
02676         wcscpy(lpStringPtr, CurrentService->lpServiceName);
02677         lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
02678         lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
02679 
02680         /* Copy the display name */
02681         wcscpy(lpStringPtr, CurrentService->lpDisplayName);
02682         lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
02683         lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
02684 
02685         /* Copy the status information */
02686         memcpy(&lpStatusPtr->ServiceStatus,
02687                &CurrentService->Status,
02688                sizeof(SERVICE_STATUS));
02689 
02690         lpStatusPtr++;
02691         dwRequiredSize += dwSize;
02692     }
02693 
02694     if (dwError == ERROR_SUCCESS)
02695     {
02696         *pcbBytesNeeded = 0;
02697         if (lpResumeHandle) *lpResumeHandle = 0;
02698     }
02699 
02700 Done:;
02701     /* Unlock the service database */
02702     ScmUnlockDatabase();
02703 
02704     DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
02705 
02706     return dwError;
02707 }
02708 
02709 
02710 /* Function 15 */
02711 DWORD ROpenSCManagerW(
02712     LPWSTR lpMachineName,
02713     LPWSTR lpDatabaseName,
02714     DWORD dwDesiredAccess,
02715     LPSC_RPC_HANDLE lpScHandle)
02716 {
02717     DWORD dwError;
02718     SC_HANDLE hHandle;
02719 
02720     DPRINT("ROpenSCManagerW() called\n");
02721     DPRINT("lpMachineName = %p\n", lpMachineName);
02722     DPRINT("lpMachineName: %S\n", lpMachineName);
02723     DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
02724     DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
02725     DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
02726 
02727     if (ScmShutdown)
02728         return ERROR_SHUTDOWN_IN_PROGRESS;
02729 
02730     if (!lpScHandle)
02731         return ERROR_INVALID_PARAMETER;
02732 
02733     dwError = ScmCreateManagerHandle(lpDatabaseName,
02734                                      &hHandle);
02735     if (dwError != ERROR_SUCCESS)
02736     {
02737         DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
02738         return dwError;
02739     }
02740 
02741     /* Check the desired access */
02742     dwError = ScmCheckAccess(hHandle,
02743                              dwDesiredAccess | SC_MANAGER_CONNECT);
02744     if (dwError != ERROR_SUCCESS)
02745     {
02746         DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
02747         HeapFree(GetProcessHeap(), 0, hHandle);
02748         return dwError;
02749     }
02750 
02751     *lpScHandle = (SC_RPC_HANDLE)hHandle;
02752     DPRINT("*hScm = %p\n", *lpScHandle);
02753 
02754     DPRINT("ROpenSCManagerW() done\n");
02755 
02756     return ERROR_SUCCESS;
02757 }
02758 
02759 
02760 /* Function 16 */
02761 DWORD ROpenServiceW(
02762     SC_RPC_HANDLE hSCManager,
02763     LPWSTR lpServiceName,
02764     DWORD dwDesiredAccess,
02765     LPSC_RPC_HANDLE lpServiceHandle)
02766 {
02767     PSERVICE lpService;
02768     PMANAGER_HANDLE hManager;
02769     SC_HANDLE hHandle;
02770     DWORD dwError = ERROR_SUCCESS;
02771 
02772     DPRINT("ROpenServiceW() called\n");
02773     DPRINT("hSCManager = %p\n", hSCManager);
02774     DPRINT("lpServiceName = %p\n", lpServiceName);
02775     DPRINT("lpServiceName: %S\n", lpServiceName);
02776     DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
02777 
02778     if (ScmShutdown)
02779         return ERROR_SHUTDOWN_IN_PROGRESS;
02780 
02781     hManager = ScmGetServiceManagerFromHandle(hSCManager);
02782     if (hManager == NULL)
02783     {
02784         DPRINT1("Invalid service manager handle!\n");
02785         return ERROR_INVALID_HANDLE;
02786     }
02787 
02788     if (!lpServiceHandle)
02789         return ERROR_INVALID_PARAMETER;
02790 
02791     if (!lpServiceName)
02792         return ERROR_INVALID_ADDRESS;
02793 
02794     /* Lock the service database exclusive */
02795     ScmLockDatabaseExclusive();
02796 
02797     /* Get service database entry */
02798     lpService = ScmGetServiceEntryByName(lpServiceName);
02799     if (lpService == NULL)
02800     {
02801         DPRINT("Could not find a service!\n");
02802         dwError = ERROR_SERVICE_DOES_NOT_EXIST;
02803         goto Done;
02804     }
02805 
02806     /* Create a service handle */
02807     dwError = ScmCreateServiceHandle(lpService,
02808                                      &hHandle);
02809     if (dwError != ERROR_SUCCESS)
02810     {
02811         DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
02812         goto Done;
02813     }
02814 
02815     /* Check the desired access */
02816     dwError = ScmCheckAccess(hHandle,
02817                              dwDesiredAccess);
02818     if (dwError != ERROR_SUCCESS)
02819     {
02820         DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
02821         HeapFree(GetProcessHeap(), 0, hHandle);
02822         goto Done;
02823     }
02824 
02825     lpService->dwRefCount++;
02826     DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
02827 
02828     *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
02829     DPRINT("*hService = %p\n", *lpServiceHandle);
02830 
02831 Done:;
02832     /* Unlock the service database */
02833     ScmUnlockDatabase();
02834 
02835     DPRINT("ROpenServiceW() done\n");
02836 
02837     return dwError;
02838 }
02839 
02840 
02841 /* Function 17 */
02842 DWORD RQueryServiceConfigW(
02843     SC_RPC_HANDLE hService,
02844     LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
02845     DWORD cbBufSize,
02846     LPBOUNDED_DWORD_8K pcbBytesNeeded)
02847 {
02848     LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
02849     DWORD dwError = ERROR_SUCCESS;
02850     PSERVICE_HANDLE hSvc;
02851     PSERVICE lpService = NULL;
02852     HKEY hServiceKey = NULL;
02853     LPWSTR lpImagePath = NULL;
02854     LPWSTR lpServiceStartName = NULL;
02855     LPWSTR lpDependencies = NULL;
02856     DWORD dwDependenciesLength = 0;
02857     DWORD dwRequiredSize;
02858     LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
02859     WCHAR lpEmptyString[] = {0,0};
02860     LPWSTR lpStr;
02861 
02862     DPRINT("RQueryServiceConfigW() called\n");
02863 
02864     if (ScmShutdown)
02865         return ERROR_SHUTDOWN_IN_PROGRESS;
02866 
02867     hSvc = ScmGetServiceFromHandle(hService);
02868     if (hSvc == NULL)
02869     {
02870         DPRINT1("Invalid service handle!\n");
02871         return ERROR_INVALID_HANDLE;
02872     }
02873 
02874     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
02875                                   SERVICE_QUERY_CONFIG))
02876     {
02877         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
02878         return ERROR_ACCESS_DENIED;
02879     }
02880 
02881     lpService = hSvc->ServiceEntry;
02882     if (lpService == NULL)
02883     {
02884         DPRINT("lpService == NULL!\n");
02885         return ERROR_INVALID_HANDLE;
02886     }
02887 
02888     /* Lock the service database shared */
02889     ScmLockDatabaseShared();
02890 
02891     dwError = ScmOpenServiceKey(lpService->lpServiceName,
02892                                 KEY_READ,
02893                                 &hServiceKey);
02894     if (dwError != ERROR_SUCCESS)
02895         goto Done;
02896 
02897     /* Read the image path */
02898     dwError = ScmReadString(hServiceKey,
02899                             L"ImagePath",
02900                             &lpImagePath);
02901     if (dwError != ERROR_SUCCESS)
02902         goto Done;
02903 
02904     /* Read the service start name */
02905     ScmReadString(hServiceKey,
02906                   L"ObjectName",
02907                   &lpServiceStartName);
02908 
02909     /* Read the dependencies */
02910     ScmReadDependencies(hServiceKey,
02911                         &lpDependencies,
02912                         &dwDependenciesLength);
02913 
02914     dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
02915 
02916     if (lpImagePath != NULL)
02917         dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
02918     else
02919         dwRequiredSize += 2 * sizeof(WCHAR);
02920 
02921     if (lpService->lpGroup != NULL)
02922         dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
02923     else
02924         dwRequiredSize += 2 * sizeof(WCHAR);
02925 
02926     if (lpDependencies != NULL)
02927         dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
02928     else
02929         dwRequiredSize += 2 * sizeof(WCHAR);
02930 
02931     if (lpServiceStartName != NULL)
02932         dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
02933     else
02934         dwRequiredSize += 2 * sizeof(WCHAR);
02935 
02936     if (lpService->lpDisplayName != NULL)
02937         dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
02938     else
02939         dwRequiredSize += 2 * sizeof(WCHAR);
02940 
02941     if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
02942     {
02943         dwError = ERROR_INSUFFICIENT_BUFFER;
02944     }
02945     else
02946     {
02947         lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
02948         lpConfig->dwServiceType = lpService->Status.dwServiceType;
02949         lpConfig->dwStartType = lpService->dwStartType;
02950         lpConfig->dwErrorControl = lpService->dwErrorControl;
02951         lpConfig->dwTagId = lpService->dwTag;
02952 
02953         lpStr = (LPWSTR)(lpConfig + 1);
02954 
02955         /* Append the image path */
02956         if (lpImagePath != NULL)
02957         {
02958             wcscpy(lpStr, lpImagePath);
02959         }
02960         else
02961         {
02962             wcscpy(lpStr, lpEmptyString);
02963         }
02964 
02965         lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
02966         lpStr += (wcslen(lpStr) + 1);
02967 
02968         /* Append the group name */
02969         if (lpService->lpGroup != NULL)
02970         {
02971             wcscpy(lpStr, lpService->lpGroup->lpGroupName);
02972         }
02973         else
02974         {
02975             wcscpy(lpStr, lpEmptyString);
02976         }
02977 
02978         lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
02979         lpStr += (wcslen(lpStr) + 1);
02980 
02981         /* Append Dependencies */
02982         if (lpDependencies != NULL)
02983         {
02984             memcpy(lpStr,
02985                    lpDependencies,
02986                    dwDependenciesLength * sizeof(WCHAR));
02987         }
02988         else
02989         {
02990             wcscpy(lpStr, lpEmptyString);
02991         }
02992 
02993         lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
02994         if (lpDependencies != NULL)
02995             lpStr += dwDependenciesLength * sizeof(WCHAR);
02996         else
02997             lpStr += (wcslen(lpStr) + 1);
02998 
02999         /* Append the service start name */
03000         if (lpServiceStartName != NULL)
03001         {
03002             wcscpy(lpStr, lpServiceStartName);
03003         }
03004         else
03005         {
03006             wcscpy(lpStr, lpEmptyString);
03007         }
03008 
03009         lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
03010         lpStr += (wcslen(lpStr) + 1);
03011 
03012         /* Append the display name */
03013         if (lpService->lpDisplayName != NULL)
03014         {
03015             wcscpy(lpStr, lpService->lpDisplayName);
03016         }
03017         else
03018         {
03019             wcscpy(lpStr, lpEmptyString);
03020         }
03021 
03022         lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
03023     }
03024 
03025     if (pcbBytesNeeded != NULL)
03026         *pcbBytesNeeded = dwRequiredSize;
03027 
03028 Done:;
03029     /* Unlock the service database */
03030     ScmUnlockDatabase();
03031 
03032     if (lpImagePath != NULL)
03033         HeapFree(GetProcessHeap(), 0, lpImagePath);
03034 
03035     if (lpServiceStartName != NULL)
03036         HeapFree(GetProcessHeap(), 0, lpServiceStartName);
03037 
03038     if (lpDependencies != NULL)
03039         HeapFree(GetProcessHeap(), 0, lpDependencies);
03040 
03041     if (hServiceKey != NULL)
03042         RegCloseKey(hServiceKey);
03043 
03044     DPRINT("RQueryServiceConfigW() done\n");
03045 
03046     return dwError;
03047 }
03048 
03049 
03050 /* Function 18 */
03051 DWORD RQueryServiceLockStatusW(
03052     SC_RPC_HANDLE hSCManager,
03053     LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
03054     DWORD cbBufSize,
03055     LPBOUNDED_DWORD_4K pcbBytesNeeded)
03056 {
03057     UNIMPLEMENTED;
03058     return ERROR_CALL_NOT_IMPLEMENTED;
03059 }
03060 
03061 
03062 /* Function 19 */
03063 DWORD RStartServiceW(
03064     SC_RPC_HANDLE hService,
03065     DWORD argc,
03066     LPSTRING_PTRSW argv)
03067 {
03068     DWORD dwError = ERROR_SUCCESS;
03069     PSERVICE_HANDLE hSvc;
03070     PSERVICE lpService = NULL;
03071     DWORD i;
03072 
03073     DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
03074     DPRINT("  argc: %lu\n", argc);
03075     if (argv != NULL)
03076     {
03077         for (i = 0; i < argc; i++)
03078         {
03079             DPRINT("  argv[%lu]: %S\n", i, argv[i]);
03080         }
03081     }
03082 
03083     if (ScmShutdown)
03084         return ERROR_SHUTDOWN_IN_PROGRESS;
03085 
03086     hSvc = ScmGetServiceFromHandle(hService);
03087     if (hSvc == NULL)
03088     {
03089         DPRINT1("Invalid service handle!\n");
03090         return ERROR_INVALID_HANDLE;
03091     }
03092 
03093     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
03094                                   SERVICE_START))
03095     {
03096         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
03097         return ERROR_ACCESS_DENIED;
03098     }
03099 
03100     lpService = hSvc->ServiceEntry;
03101     if (lpService == NULL)
03102     {
03103         DPRINT("lpService == NULL!\n");
03104         return ERROR_INVALID_HANDLE;
03105     }
03106 
03107     if (lpService->dwStartType == SERVICE_DISABLED)
03108         return ERROR_SERVICE_DISABLED;
03109 
03110     if (lpService->bDeleted)
03111         return ERROR_SERVICE_MARKED_FOR_DELETE;
03112 
03113     /* Start the service */
03114     dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
03115 
03116     return dwError;
03117 }
03118 
03119 
03120 /* Function 20 */
03121 DWORD RGetServiceDisplayNameW(
03122     SC_RPC_HANDLE hSCManager,
03123     LPCWSTR lpServiceName,
03124     LPWSTR lpDisplayName,
03125     DWORD *lpcchBuffer)
03126 {
03127 //    PMANAGER_HANDLE hManager;
03128     PSERVICE lpService;
03129     DWORD dwLength;
03130     DWORD dwError;
03131 
03132     DPRINT("RGetServiceDisplayNameW() called\n");
03133     DPRINT("hSCManager = %p\n", hSCManager);
03134     DPRINT("lpServiceName: %S\n", lpServiceName);
03135     DPRINT("lpDisplayName: %p\n", lpDisplayName);
03136     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
03137 
03138 //    hManager = (PMANAGER_HANDLE)hSCManager;
03139 //    if (hManager->Handle.Tag != MANAGER_TAG)
03140 //    {
03141 //        DPRINT("Invalid manager handle!\n");
03142 //        return ERROR_INVALID_HANDLE;
03143 //    }
03144 
03145     /* Get service database entry */
03146     lpService = ScmGetServiceEntryByName(lpServiceName);
03147     if (lpService == NULL)
03148     {
03149         DPRINT("Could not find a service!\n");
03150 
03151         /* If the service could not be found and lpcchBuffer is less than 2, windows
03152            puts null in lpDisplayName and puts 2 in lpcchBuffer */
03153         if (*lpcchBuffer < 2)
03154         {
03155             *lpcchBuffer = 2;
03156             if (lpDisplayName != NULL)
03157             {
03158                 *lpDisplayName = '\0';
03159             }
03160         }
03161 
03162         return ERROR_SERVICE_DOES_NOT_EXIST;
03163     }
03164 
03165     if (!lpService->lpDisplayName)
03166     {
03167         dwLength = wcslen(lpService->lpServiceName);
03168 
03169         if (lpDisplayName != NULL &&
03170             *lpcchBuffer > dwLength)
03171         {
03172             wcscpy(lpDisplayName, lpService->lpServiceName);
03173         }
03174     }
03175     else
03176     {
03177         dwLength = wcslen(lpService->lpDisplayName);
03178 
03179         if (lpDisplayName != NULL &&
03180             *lpcchBuffer > dwLength)
03181         {
03182             wcscpy(lpDisplayName, lpService->lpDisplayName);
03183         }
03184     }
03185 
03186     dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
03187 
03188     *lpcchBuffer = dwLength;
03189 
03190     return dwError;
03191 }
03192 
03193 
03194 /* Function 21 */
03195 DWORD RGetServiceKeyNameW(
03196     SC_RPC_HANDLE hSCManager,
03197     LPCWSTR lpDisplayName,
03198     LPWSTR lpServiceName,
03199     DWORD *lpcchBuffer)
03200 {
03201 //    PMANAGER_HANDLE hManager;
03202     PSERVICE lpService;
03203     DWORD dwLength;
03204     DWORD dwError;
03205 
03206     DPRINT("RGetServiceKeyNameW() called\n");
03207     DPRINT("hSCManager = %p\n", hSCManager);
03208     DPRINT("lpDisplayName: %S\n", lpDisplayName);
03209     DPRINT("lpServiceName: %p\n", lpServiceName);
03210     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
03211 
03212 //    hManager = (PMANAGER_HANDLE)hSCManager;
03213 //    if (hManager->Handle.Tag != MANAGER_TAG)
03214 //    {
03215 //        DPRINT("Invalid manager handle!\n");
03216 //        return ERROR_INVALID_HANDLE;
03217 //    }
03218 
03219     /* Get service database entry */
03220     lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
03221     if (lpService == NULL)
03222     {
03223         DPRINT("Could not find a service!\n");
03224 
03225         /* If the service could not be found and lpcchBuffer is less than 2, windows
03226            puts null in lpDisplayName and puts 2 in lpcchBuffer */
03227         if (*lpcchBuffer < 2)
03228         {
03229             *lpcchBuffer = 2;
03230             if (lpServiceName != NULL)
03231             {
03232                 *lpServiceName = '\0';
03233             }
03234         }
03235 
03236         return ERROR_SERVICE_DOES_NOT_EXIST;
03237     }
03238 
03239     dwLength = wcslen(lpService->lpServiceName);
03240 
03241     if (lpServiceName != NULL &&
03242         *lpcchBuffer > dwLength)
03243     {
03244         wcscpy(lpServiceName, lpService->lpServiceName);
03245         *lpcchBuffer = dwLength;
03246         return ERROR_SUCCESS;
03247     }
03248 
03249     dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
03250 
03251     *lpcchBuffer = dwLength;
03252 
03253     return dwError;
03254 }
03255 
03256 
03257 /* Function 22 */
03258 DWORD RI_ScSetServiceBitsA(
03259     RPC_SERVICE_STATUS_HANDLE hServiceStatus,
03260     DWORD dwServiceBits,
03261     int bSetBitsOn,
03262     int bUpdateImmediately,
03263     char *lpString)
03264 {
03265     UNIMPLEMENTED;
03266     return ERROR_CALL_NOT_IMPLEMENTED;
03267 }
03268 
03269 
03270 /* Function 23 */
03271 DWORD RChangeServiceConfigA(
03272     SC_RPC_HANDLE hService,
03273     DWORD dwServiceType,
03274     DWORD dwStartType,
03275     DWORD dwErrorControl,
03276     LPSTR lpBinaryPathName,
03277     LPSTR lpLoadOrderGroup,
03278     LPDWORD lpdwTagId,
03279     LPSTR lpDependencies,
03280     DWORD dwDependSize,
03281     LPSTR lpServiceStartName,
03282     LPBYTE lpPassword,
03283     DWORD dwPwSize,
03284     LPSTR lpDisplayName)
03285 {
03286     DWORD dwError = ERROR_SUCCESS;
03287     PSERVICE_HANDLE hSvc;
03288     PSERVICE lpService = NULL;
03289     HKEY hServiceKey = NULL;
03290     LPWSTR lpDisplayNameW = NULL;
03291     LPWSTR lpBinaryPathNameW = NULL;
03292     LPWSTR lpCanonicalImagePathW = NULL;
03293     LPWSTR lpLoadOrderGroupW = NULL;
03294     LPWSTR lpDependenciesW = NULL;
03295     // LPWSTR lpPasswordW = NULL;
03296 
03297     DPRINT("RChangeServiceConfigA() called\n");
03298     DPRINT("dwServiceType = %lu\n", dwServiceType);
03299     DPRINT("dwStartType = %lu\n", dwStartType);
03300     DPRINT("dwErrorControl = %lu\n", dwErrorControl);
03301     DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
03302     DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
03303     DPRINT("lpDisplayName = %s\n", lpDisplayName);
03304 
03305     if (ScmShutdown)
03306         return ERROR_SHUTDOWN_IN_PROGRESS;
03307 
03308     hSvc = ScmGetServiceFromHandle(hService);
03309     if (hSvc == NULL)
03310     {
03311         DPRINT1("Invalid service handle!\n");
03312         return ERROR_INVALID_HANDLE;
03313     }
03314 
03315     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
03316                                   SERVICE_CHANGE_CONFIG))
03317     {
03318         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
03319         return ERROR_ACCESS_DENIED;
03320     }
03321 
03322     lpService = hSvc->ServiceEntry;
03323     if (lpService == NULL)
03324     {
03325         DPRINT("lpService == NULL!\n");
03326         return ERROR_INVALID_HANDLE;
03327     }
03328 
03329     /* Lock the service database exclusively */
03330     ScmLockDatabaseExclusive();
03331 
03332     if (lpService->bDeleted)
03333     {
03334         DPRINT("The service has already been marked for delete!\n");
03335         dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
03336         goto done;
03337     }
03338 
03339     /* Open the service key */
03340     dwError = ScmOpenServiceKey(lpService->szServiceName,
03341                                 KEY_SET_VALUE,
03342                                 &hServiceKey);
03343     if (dwError != ERROR_SUCCESS)
03344         goto done;
03345 
03346     /* Write service data to the registry */
03347 
03348     if (lpDisplayName != NULL && *lpDisplayName != 0)
03349     {
03350         /* Set the display name */
03351         lpDisplayNameW = HeapAlloc(GetProcessHeap(),
03352                                    0,
03353                                    (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
03354         if (lpDisplayNameW == NULL)
03355         {
03356             dwError = ERROR_NOT_ENOUGH_MEMORY;
03357             goto done;
03358         }
03359 
03360         MultiByteToWideChar(CP_ACP,
03361                             0,
03362                             lpDisplayName,
03363                             -1,
03364                             lpDisplayNameW,
03365                             strlen(lpDisplayName) + 1);
03366 
03367         RegSetValueExW(hServiceKey,
03368                        L"DisplayName",
03369                        0,
03370                        REG_SZ,
03371                        (LPBYTE)lpDisplayNameW,
03372                        (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
03373 
03374         /* Update lpService->lpDisplayName */
03375         if (lpService->lpDisplayName)
03376             HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
03377 
03378         lpService->lpDisplayName = lpDisplayNameW;
03379     }
03380 
03381     if (dwServiceType != SERVICE_NO_CHANGE)
03382     {
03383         /* Set the service type */
03384         dwError = RegSetValueExW(hServiceKey,
03385                                  L"Type",
03386                                  0,
03387                                  REG_DWORD,
03388                                  (LPBYTE)&dwServiceType,
03389                                  sizeof(DWORD));
03390         if (dwError != ERROR_SUCCESS)
03391             goto done;
03392 
03393         lpService->Status.dwServiceType = dwServiceType;
03394     }
03395 
03396     if (dwStartType != SERVICE_NO_CHANGE)
03397     {
03398         /* Set the start value */
03399         dwError = RegSetValueExW(hServiceKey,
03400                                  L"Start",
03401                                  0,
03402                                  REG_DWORD,
03403                                  (LPBYTE)&dwStartType,
03404                                  sizeof(DWORD));
03405         if (dwError != ERROR_SUCCESS)
03406             goto done;
03407 
03408         lpService->dwStartType = dwStartType;
03409     }
03410 
03411     if (dwErrorControl != SERVICE_NO_CHANGE)
03412     {
03413         /* Set the error control value */
03414         dwError = RegSetValueExW(hServiceKey,
03415                                  L"ErrorControl",
03416                                  0,
03417                                  REG_DWORD,
03418                                  (LPBYTE)&dwErrorControl,
03419                                  sizeof(DWORD));
03420         if (dwError != ERROR_SUCCESS)
03421             goto done;
03422 
03423         lpService->dwErrorControl = dwErrorControl;
03424     }
03425 
03426     if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
03427     {
03428         /* Set the image path */
03429         lpBinaryPathNameW = HeapAlloc(GetProcessHeap(),
03430                                       0,
03431                                       (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR));
03432         if (lpBinaryPathNameW == NULL)
03433         {
03434             dwError = ERROR_NOT_ENOUGH_MEMORY;
03435             goto done;
03436         }
03437 
03438         MultiByteToWideChar(CP_ACP,
03439                             0,
03440                             lpBinaryPathName,
03441                             -1,
03442                             lpBinaryPathNameW,
03443                             strlen(lpBinaryPathName) + 1);
03444 
03445         if (lpService->Status.dwServiceType & SERVICE_DRIVER)
03446         {
03447             dwError = ScmCanonDriverImagePath(lpService->dwStartType,
03448                                               lpBinaryPathNameW,
03449                                               &lpCanonicalImagePathW);
03450 
03451             HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
03452 
03453             if (dwError != ERROR_SUCCESS)
03454                 goto done;
03455 
03456             lpBinaryPathNameW = lpCanonicalImagePathW;
03457         }
03458 
03459         dwError = RegSetValueExW(hServiceKey,
03460                                  L"ImagePath",
03461                                  0,
03462                                  REG_EXPAND_SZ,
03463                                  (LPBYTE)lpBinaryPathNameW,
03464                                  (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
03465 
03466         HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
03467 
03468         if (dwError != ERROR_SUCCESS)
03469             goto done;
03470     }
03471 
03472     /* Set the group name */
03473     if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
03474     {
03475         lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
03476                                       0,
03477                                       (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
03478         if (lpLoadOrderGroupW == NULL)
03479         {
03480             dwError = ERROR_NOT_ENOUGH_MEMORY;
03481             goto done;
03482         }
03483 
03484         MultiByteToWideChar(CP_ACP,
03485                             0,
03486                             lpLoadOrderGroup,
03487                             -1,
03488                             lpLoadOrderGroupW,
03489                             strlen(lpLoadOrderGroup) + 1);
03490 
03491         dwError = RegSetValueExW(hServiceKey,
03492                                  L"Group",
03493                                  0,
03494                                  REG_SZ,
03495                                  (LPBYTE)lpLoadOrderGroupW,
03496                                  (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
03497         if (dwError != ERROR_SUCCESS)
03498         {
03499             HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
03500             goto done;
03501         }
03502 
03503         dwError = ScmSetServiceGroup(lpService,
03504                                      lpLoadOrderGroupW);
03505 
03506         HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
03507 
03508         if (dwError != ERROR_SUCCESS)
03509             goto done;
03510     }
03511 
03512     if (lpdwTagId != NULL)
03513     {
03514         dwError = ScmAssignNewTag(lpService);
03515         if (dwError != ERROR_SUCCESS)
03516             goto done;
03517 
03518         dwError = RegSetValueExW(hServiceKey,
03519                                  L"Tag",
03520                                  0,
03521                                  REG_DWORD,
03522                                  (LPBYTE)&lpService->dwTag,
03523                                  sizeof(DWORD));
03524         if (dwError != ERROR_SUCCESS)
03525             goto done;
03526 
03527         *lpdwTagId = lpService->dwTag;
03528     }
03529 
03530     /* Write dependencies */
03531     if (lpDependencies != NULL && *lpDependencies != 0)
03532     {
03533         lpDependenciesW = HeapAlloc(GetProcessHeap(),
03534                                     0,
03535                                     (strlen(lpDependencies) + 1) * sizeof(WCHAR));
03536         if (lpDependenciesW == NULL)
03537         {
03538             dwError = ERROR_NOT_ENOUGH_MEMORY;
03539             goto done;
03540         }
03541 
03542         MultiByteToWideChar(CP_ACP,
03543                             0,
03544                             lpDependencies,
03545                             dwDependSize,
03546                             lpDependenciesW,
03547                             strlen(lpDependencies) + 1);
03548 
03549         dwError = ScmWriteDependencies(hServiceKey,
03550                                        (LPWSTR)lpDependenciesW,
03551                                        dwDependSize);
03552 
03553         HeapFree(GetProcessHeap(), 0, lpDependenciesW);
03554     }
03555 
03556     if (lpPassword != NULL)
03557     {
03558         /* FIXME: Write password */
03559     }
03560 
03561 done:
03562     /* Unlock the service database */
03563     ScmUnlockDatabase();
03564 
03565     if (hServiceKey != NULL)
03566         RegCloseKey(hServiceKey);
03567 
03568     DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
03569 
03570     return dwError;
03571 }
03572 
03573 
03574 /* Function 24 */
03575 DWORD RCreateServiceA(
03576     SC_RPC_HANDLE hSCManager,
03577     LPSTR lpServiceName,
03578     LPSTR lpDisplayName,
03579     DWORD dwDesiredAccess,
03580     DWORD dwServiceType,
03581     DWORD dwStartType,
03582     DWORD dwErrorControl,
03583     LPSTR lpBinaryPathName,
03584     LPSTR lpLoadOrderGroup,
03585     LPDWORD lpdwTagId,
03586     LPBYTE lpDependencies,
03587     DWORD dwDependSize,
03588     LPSTR lpServiceStartName,
03589     LPBYTE lpPassword,
03590     DWORD dwPwSize,
03591     LPSC_RPC_HANDLE lpServiceHandle)
03592 {
03593     DWORD dwError = ERROR_SUCCESS;
03594     LPWSTR lpServiceNameW = NULL;
03595     LPWSTR lpDisplayNameW = NULL;
03596     LPWSTR lpBinaryPathNameW = NULL;
03597     LPWSTR lpLoadOrderGroupW = NULL;
03598     LPWSTR lpDependenciesW = NULL;
03599     LPWSTR lpServiceStartNameW = NULL;
03600     DWORD dwDependenciesLength = 0;
03601     DWORD dwLength;
03602     int len;
03603     LPCSTR lpStr;
03604 
03605     if (lpServiceName)
03606     {
03607         len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
03608         lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
03609         if (!lpServiceNameW)
03610         {
03611             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03612             goto cleanup;
03613         }
03614         MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
03615     }
03616 
03617     if (lpDisplayName)
03618     {
03619         len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
03620         lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
03621         if (!lpDisplayNameW)
03622         {
03623             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03624             goto cleanup;
03625         }
03626         MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
03627     }
03628 
03629     if (lpBinaryPathName)
03630     {
03631         len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
03632         lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
03633         if (!lpBinaryPathNameW)
03634         {
03635             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03636             goto cleanup;
03637         }
03638         MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
03639     }
03640 
03641     if (lpLoadOrderGroup)
03642     {
03643         len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
03644         lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
03645         if (!lpLoadOrderGroupW)
03646         {
03647             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03648             goto cleanup;
03649         }
03650         MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
03651     }
03652 
03653     if (lpDependencies)
03654     {
03655         lpStr = (LPCSTR)lpDependencies;
03656         while (*lpStr)
03657         {
03658             dwLength = strlen(lpStr) + 1;
03659             dwDependenciesLength += dwLength;
03660             lpStr = lpStr + dwLength;
03661         }
03662         dwDependenciesLength++;
03663 
03664         lpDependenciesW = HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength * sizeof(WCHAR));
03665         if (!lpDependenciesW)
03666         {
03667             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03668             goto cleanup;
03669         }
03670         MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
03671     }
03672 
03673     if (lpServiceStartName)
03674     {
03675         len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
03676         lpServiceStartNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
03677         if (!lpServiceStartNameW)
03678         {
03679             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03680             goto cleanup;
03681         }
03682         MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
03683     }
03684 
03685     dwError = RCreateServiceW(hSCManager,
03686                               lpServiceNameW,
03687                               lpDisplayNameW,
03688                               dwDesiredAccess,
03689                               dwServiceType,
03690                               dwStartType,
03691                               dwErrorControl,
03692                               lpBinaryPathNameW,
03693                               lpLoadOrderGroupW,
03694                               lpdwTagId,
03695                               (LPBYTE)lpDependenciesW,
03696                               dwDependenciesLength,
03697                               lpServiceStartNameW,
03698                               lpPassword,
03699                               dwPwSize,
03700                               lpServiceHandle);
03701 
03702 cleanup:
03703     if (lpServiceNameW !=NULL)
03704         HeapFree(GetProcessHeap(), 0, lpServiceNameW);
03705 
03706     if (lpDisplayNameW != NULL)
03707         HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
03708 
03709     if (lpBinaryPathNameW != NULL)
03710         HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
03711 
03712     if (lpLoadOrderGroupW != NULL)
03713         HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
03714 
03715     if (lpDependenciesW != NULL)
03716         HeapFree(GetProcessHeap(), 0, lpDependenciesW);
03717 
03718     if (lpServiceStartNameW != NULL)
03719         HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
03720 
03721     return dwError;
03722 }
03723 
03724 
03725 /* Function 25 */
03726 DWORD REnumDependentServicesA(
03727     SC_RPC_HANDLE hService,
03728     DWORD dwServiceState,
03729     LPBYTE lpServices,
03730     DWORD cbBufSize,
03731     LPBOUNDED_DWORD_256K pcbBytesNeeded,
03732     LPBOUNDED_DWORD_256K lpServicesReturned)
03733 {
03734     DWORD dwError = ERROR_SUCCESS;
03735     DWORD dwServicesReturned = 0;
03736     DWORD dwServiceCount;
03737     HKEY hServicesKey = NULL;
03738     PSERVICE_HANDLE hSvc;
03739     PSERVICE lpService = NULL;
03740     PSERVICE *lpServicesArray = NULL;
03741     LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
03742     LPSTR lpStr;
03743 
03744     *pcbBytesNeeded = 0;
03745     *lpServicesReturned = 0;
03746 
03747     DPRINT("REnumDependentServicesA() called\n");
03748 
03749     hSvc = ScmGetServiceFromHandle(hService);
03750     if (hSvc == NULL)
03751     {
03752         DPRINT1("Invalid service handle!\n");
03753         return ERROR_INVALID_HANDLE;
03754     }
03755 
03756     lpService = hSvc->ServiceEntry;
03757 
03758     /* Check access rights */
03759     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
03760                                   SC_MANAGER_ENUMERATE_SERVICE))
03761     {
03762         DPRINT("Insufficient access rights! 0x%lx\n",
03763                hSvc->Handle.DesiredAccess);
03764         return ERROR_ACCESS_DENIED;
03765     }
03766 
03767     /* Open the Services Reg key */
03768     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
03769                             L"System\\CurrentControlSet\\Services",
03770                             0,
03771                             KEY_READ,
03772                             &hServicesKey);
03773 
03774     if (dwError != ERROR_SUCCESS)
03775         return dwError;
03776 
03777     /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
03778              both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
03779              are the same for both. Verified in WINXP. */
03780 
03781     /* First determine the bytes needed and get the number of dependent services*/
03782     dwError = Int_EnumDependentServicesW(hServicesKey,
03783                                          lpService,
03784                                          dwServiceState,
03785                                          NULL,
03786                                          pcbBytesNeeded,
03787                                          &dwServicesReturned);
03788     if (dwError != ERROR_SUCCESS)
03789         goto Done;
03790 
03791     /* If buffer size is less than the bytes needed or pointer is null*/
03792     if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
03793     {
03794         dwError = ERROR_MORE_DATA;
03795         goto Done;
03796     }
03797 
03798     /* Allocate memory for array of service pointers */
03799     lpServicesArray = HeapAlloc(GetProcessHeap(),
03800                                 0,
03801                                 (dwServicesReturned + 1) * sizeof(PSERVICE));
03802     if (!lpServicesArray)
03803     {
03804         DPRINT("Could not allocate a buffer!!\n");
03805         dwError = ERROR_NOT_ENOUGH_MEMORY;
03806         goto Done;
03807     }
03808 
03809     dwServicesReturned = 0;
03810     *pcbBytesNeeded = 0;
03811 
03812     dwError = Int_EnumDependentServicesW(hServicesKey,
03813                                          lpService,
03814                                          dwServiceState,
03815                                          lpServicesArray,
03816                                          pcbBytesNeeded,
03817                                          &dwServicesReturned);
03818     if (dwError != ERROR_SUCCESS)
03819     {
03820         goto Done;
03821     }
03822 
03823     lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
03824     lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
03825 
03826     /* Copy EnumDepenedentService to Buffer */
03827     for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
03828     {
03829         lpService = lpServicesArray[dwServiceCount];
03830 
03831         /* Copy the status info */
03832         memcpy(&lpServicesPtr->ServiceStatus,
03833                &lpService->Status,
03834                sizeof(SERVICE_STATUS));
03835 
03836         /* Copy display name */
03837         WideCharToMultiByte(CP_ACP,
03838                             0,
03839                             lpService->lpDisplayName,
03840                             -1,
03841                             lpStr,
03842                             wcslen(lpService->lpDisplayName),
03843                             0,
03844                             0);
03845         lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
03846         lpStr += strlen(lpStr) + 1;
03847 
03848         /* Copy service name */
03849         WideCharToMultiByte(CP_ACP,
03850                             0,
03851                             lpService->lpServiceName,
03852                             -1,
03853                             lpStr,
03854                             wcslen(lpService->lpServiceName),
03855                             0,
03856                             0);
03857         lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
03858         lpStr += strlen(lpStr) + 1;
03859 
03860         lpServicesPtr ++;
03861     }
03862 
03863     *lpServicesReturned = dwServicesReturned;
03864 
03865 Done:
03866     if (lpServicesArray)
03867         HeapFree(GetProcessHeap(), 0, lpServicesArray);
03868 
03869     RegCloseKey(hServicesKey);
03870 
03871     DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
03872 
03873     return dwError;
03874 }
03875 
03876 
03877 /* Function 26 */
03878 DWORD REnumServicesStatusA(
03879     SC_RPC_HANDLE hSCManager,
03880     DWORD dwServiceType,
03881     DWORD dwServiceState,
03882     LPBYTE lpBuffer,
03883     DWORD dwBufSize,
03884     LPBOUNDED_DWORD_256K pcbBytesNeeded,
03885     LPBOUNDED_DWORD_256K lpServicesReturned,
03886     LPBOUNDED_DWORD_256K lpResumeHandle)
03887 {
03888     LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
03889     LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
03890     LPWSTR lpStringPtrW;
03891     LPSTR lpStringPtrA;
03892     DWORD dwError;
03893     DWORD dwServiceCount;
03894 
03895     DPRINT("REnumServicesStatusA() called\n");
03896 
03897     if ((dwBufSize > 0) && (lpBuffer))
03898     {
03899         lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
03900         if (!lpStatusPtrW)
03901         {
03902             DPRINT("Failed to allocate buffer!\n");
03903             return ERROR_NOT_ENOUGH_MEMORY;
03904         }
03905     }
03906 
03907     dwError = REnumServicesStatusW(hSCManager,
03908                                    dwServiceType,
03909                                    dwServiceState,
03910                                    (LPBYTE)lpStatusPtrW,
03911                                    dwBufSize,
03912                                    pcbBytesNeeded,
03913                                    lpServicesReturned,
03914                                    lpResumeHandle);
03915 
03916     /* if no services were returned then we are Done */
03917     if (*lpServicesReturned == 0)
03918         goto Done;
03919 
03920     lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
03921     lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
03922                   *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
03923     lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
03924                   *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
03925 
03926     for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
03927     {
03928         /* Copy the service name */
03929         WideCharToMultiByte(CP_ACP,
03930                             0,
03931                             lpStringPtrW,
03932                             -1,
03933                             lpStringPtrA,
03934                             wcslen(lpStringPtrW),
03935                             0,
03936                             0);
03937 
03938         lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
03939         lpStringPtrA += wcslen(lpStringPtrW) + 1;
03940         lpStringPtrW += wcslen(lpStringPtrW) + 1;
03941 
03942         /* Copy the display name */
03943         WideCharToMultiByte(CP_ACP,
03944                             0,
03945                             lpStringPtrW,
03946                             -1,
03947                             lpStringPtrA,
03948                             wcslen(lpStringPtrW),
03949                             0,
03950                             0);
03951 
03952         lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
03953         lpStringPtrA += wcslen(lpStringPtrW) + 1;
03954         lpStringPtrW += wcslen(lpStringPtrW) + 1;
03955 
03956         /* Copy the status information */
03957         memcpy(&lpStatusPtrA->ServiceStatus,
03958                &lpStatusPtrW->ServiceStatus,
03959                sizeof(SERVICE_STATUS));
03960 
03961         lpStatusPtrA++;
03962     }
03963 
03964 Done:;
03965     if (lpStatusPtrW)
03966         HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
03967 
03968     DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
03969 
03970     return dwError;
03971 }
03972 
03973 
03974 /* Function 27 */
03975 DWORD ROpenSCManagerA(
03976     LPSTR lpMachineName,
03977     LPSTR lpDatabaseName,
03978     DWORD dwDesiredAccess,
03979     LPSC_RPC_HANDLE lpScHandle)
03980 {
03981     UNICODE_STRING MachineName;
03982     UNICODE_STRING DatabaseName;
03983     DWORD dwError;
03984 
03985     DPRINT("ROpenSCManagerA() called\n");
03986 
03987     if (lpMachineName)
03988         RtlCreateUnicodeStringFromAsciiz(&MachineName,
03989                                          lpMachineName);
03990 
03991     if (lpDatabaseName)
03992         RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
03993                                          lpDatabaseName);
03994 
03995     dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
03996                               lpDatabaseName ? DatabaseName.Buffer : NULL,
03997                               dwDesiredAccess,
03998                               lpScHandle);
03999 
04000     if (lpMachineName)
04001         RtlFreeUnicodeString(&MachineName);
04002 
04003     if (lpDatabaseName)
04004         RtlFreeUnicodeString(&DatabaseName);
04005 
04006     return dwError;
04007 }
04008 
04009 
04010 /* Function 28 */
04011 DWORD ROpenServiceA(
04012     SC_RPC_HANDLE hSCManager,
04013     LPSTR lpServiceName,
04014     DWORD dwDesiredAccess,
04015     LPSC_RPC_HANDLE lpServiceHandle)
04016 {
04017     UNICODE_STRING ServiceName;
04018     DWORD dwError;
04019 
04020     DPRINT("ROpenServiceA() called\n");
04021 
04022     if (lpServiceName)
04023         RtlCreateUnicodeStringFromAsciiz(&ServiceName,
04024                                          lpServiceName);
04025 
04026     dwError = ROpenServiceW(hSCManager,
04027                             lpServiceName ? ServiceName.Buffer : NULL,
04028                             dwDesiredAccess,
04029                             lpServiceHandle);
04030 
04031     if (lpServiceName)
04032         RtlFreeUnicodeString(&ServiceName);
04033 
04034     return dwError;
04035 }
04036 
04037 
04038 /* Function 29 */
04039 DWORD RQueryServiceConfigA(
04040     SC_RPC_HANDLE hService,
04041     LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
04042     DWORD cbBufSize,
04043     LPBOUNDED_DWORD_8K pcbBytesNeeded)
04044 {
04045     LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
04046     DWORD dwError = ERROR_SUCCESS;
04047     PSERVICE_HANDLE hSvc;
04048     PSERVICE lpService = NULL;
04049     HKEY hServiceKey = NULL;
04050     LPWSTR lpImagePath = NULL;
04051     LPWSTR lpServiceStartName = NULL;
04052     LPWSTR lpDependencies = NULL;
04053     DWORD dwDependenciesLength = 0;
04054     DWORD dwRequiredSize;
04055     LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
04056     CHAR lpEmptyString[]={0,0};
04057     LPSTR lpStr;
04058 
04059     DPRINT("RQueryServiceConfigA() called\n");
04060 
04061     if (ScmShutdown)
04062         return ERROR_SHUTDOWN_IN_PROGRESS;
04063 
04064     hSvc = ScmGetServiceFromHandle(hService);
04065     if (hSvc == NULL)
04066     {
04067         DPRINT1("Invalid service handle!\n");
04068         return ERROR_INVALID_HANDLE;
04069     }
04070 
04071     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
04072                                   SERVICE_QUERY_CONFIG))
04073     {
04074         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
04075         return ERROR_ACCESS_DENIED;
04076     }
04077 
04078     lpService = hSvc->ServiceEntry;
04079     if (lpService == NULL)
04080     {
04081         DPRINT("lpService == NULL!\n");
04082         return ERROR_INVALID_HANDLE;
04083     }
04084 
04085     /* Lock the service database shared */
04086     ScmLockDatabaseShared();
04087 
04088     dwError = ScmOpenServiceKey(lpService->lpServiceName,
04089                                 KEY_READ,
04090                                 &hServiceKey);
04091     if (dwError != ERROR_SUCCESS)
04092         goto Done;
04093 
04094     /* Read the image path */
04095     dwError = ScmReadString(hServiceKey,
04096                             L"ImagePath",
04097                             &lpImagePath);
04098     if (dwError != ERROR_SUCCESS)
04099         goto Done;
04100 
04101     /* Read the service start name */
04102     ScmReadString(hServiceKey,
04103                   L"ObjectName",
04104                   &lpServiceStartName);
04105 
04106     /* Read the dependencies */
04107     ScmReadDependencies(hServiceKey,
04108                         &lpDependencies,
04109                         &dwDependenciesLength);
04110 
04111     dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
04112 
04113     if (lpImagePath != NULL)
04114         dwRequiredSize += wcslen(lpImagePath) + 1;
04115     else
04116         dwRequiredSize += 2;
04117 
04118     if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
04119         dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
04120     else
04121         dwRequiredSize += 2;
04122 
04123     /* Add Dependencies length */
04124     if (lpDependencies != NULL)
04125         dwRequiredSize += dwDependenciesLength;
04126     else
04127         dwRequiredSize += 2;
04128 
04129     if (lpServiceStartName != NULL)
04130         dwRequiredSize += wcslen(lpServiceStartName) + 1;
04131     else
04132         dwRequiredSize += 2;
04133 
04134     if (lpService->lpDisplayName != NULL)
04135         dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
04136     else
04137         dwRequiredSize += 2;
04138 
04139     if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
04140     {
04141         dwError = ERROR_INSUFFICIENT_BUFFER;
04142     }
04143     else
04144     {
04145         lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
04146         lpConfig->dwServiceType = lpService->Status.dwServiceType;
04147         lpConfig->dwStartType = lpService->dwStartType;
04148         lpConfig->dwErrorControl = lpService->dwErrorControl;
04149         lpConfig->dwTagId = lpService->dwTag;
04150 
04151         lpStr = (LPSTR)(lpServiceConfig + 1);
04152 
04153         /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
04154           Verified in WINXP*/
04155 
04156         if (lpImagePath)
04157         {
04158             WideCharToMultiByte(CP_ACP,
04159                                 0,
04160                                 lpImagePath,
04161                                 -1,
04162                                 lpStr,
04163                                 wcslen(lpImagePath) + 1,
04164                                 0,
04165                                 0);
04166         }
04167         else
04168         {
04169             strcpy(lpStr, lpEmptyString);
04170         }
04171 
04172         lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
04173         lpStr += (strlen((LPSTR)lpStr) + 1);
04174 
04175         if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
04176         {
04177             WideCharToMultiByte(CP_ACP,
04178                                 0,
04179                                 lpService->lpGroup->lpGroupName,
04180                                 -1,
04181                                 lpStr,
04182                                 wcslen(lpService->lpGroup->lpGroupName) + 1,
04183                                 0,
04184                                 0);
04185         }
04186         else
04187         {
04188             strcpy(lpStr, lpEmptyString);
04189         }
04190 
04191         lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
04192         lpStr += (strlen(lpStr) + 1);
04193 
04194         /* Append Dependencies */
04195         if (lpDependencies)
04196         {
04197             WideCharToMultiByte(CP_ACP,
04198                                 0,
04199                                 lpDependencies,
04200                                 dwDependenciesLength,
04201                                 lpStr,
04202                                 dwDependenciesLength,
04203                                 0,
04204                                 0);
04205         }
04206         else
04207         {
04208             strcpy(lpStr, lpEmptyString);
04209         }
04210 
04211         lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
04212         if (lpDependencies)
04213             lpStr += dwDependenciesLength;
04214         else
04215             lpStr += (strlen(lpStr) + 1);
04216 
04217         if (lpServiceStartName)
04218         {
04219             WideCharToMultiByte(CP_ACP,
04220                                 0,
04221                                 lpServiceStartName,
04222                                 -1,
04223                                 lpStr,
04224                                 wcslen(lpServiceStartName) + 1,
04225                                 0,
04226                                 0);
04227         }
04228         else
04229         {
04230             strcpy(lpStr, lpEmptyString);
04231         }
04232 
04233         lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
04234         lpStr += (strlen(lpStr) + 1);
04235 
04236         if (lpService->lpDisplayName)
04237         {
04238             WideCharToMultiByte(CP_ACP,
04239                                 0,
04240                                 lpService->lpDisplayName,
04241                                 -1,
04242                                 lpStr,
04243                                 wcslen(lpService->lpDisplayName) + 1,
04244                                 0,
04245                                 0);
04246         }
04247         else
04248         {
04249             strcpy(lpStr, lpEmptyString);
04250         }
04251 
04252         lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
04253     }
04254 
04255     if (pcbBytesNeeded != NULL)
04256         *pcbBytesNeeded = dwRequiredSize;
04257 
04258 Done:;
04259     /* Unlock the service database */
04260     ScmUnlockDatabase();
04261 
04262     if (lpImagePath != NULL)
04263         HeapFree(GetProcessHeap(), 0, lpImagePath);
04264 
04265     if (lpServiceStartName != NULL)
04266         HeapFree(GetProcessHeap(), 0, lpServiceStartName);
04267 
04268     if (lpDependencies != NULL)
04269         HeapFree(GetProcessHeap(), 0, lpDependencies);
04270 
04271     if (hServiceKey != NULL)
04272         RegCloseKey(hServiceKey);
04273 
04274     DPRINT("RQueryServiceConfigA() done\n");
04275 
04276     return dwError;
04277 }
04278 
04279 
04280 /* Function 30 */
04281 DWORD RQueryServiceLockStatusA(
04282     SC_RPC_HANDLE hSCManager,
04283     LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
04284     DWORD cbBufSize,
04285     LPBOUNDED_DWORD_4K pcbBytesNeeded)
04286 {
04287     UNIMPLEMENTED;
04288     return ERROR_CALL_NOT_IMPLEMENTED;
04289 }
04290 
04291 
04292 /* Function 31 */
04293 DWORD RStartServiceA(
04294     SC_RPC_HANDLE hService,
04295     DWORD argc,
04296     LPSTRING_PTRSA argv)
04297 {
04298     DWORD dwError = ERROR_SUCCESS;
04299     PSERVICE_HANDLE hSvc;
04300     PSERVICE lpService = NULL;
04301     LPWSTR *lpVector = NULL;
04302     DWORD i;
04303     DWORD dwLength;
04304 
04305     DPRINT("RStartServiceA() called\n");
04306 
04307     if (ScmShutdown)
04308         return ERROR_SHUTDOWN_IN_PROGRESS;
04309 
04310     hSvc = ScmGetServiceFromHandle(hService);
04311     if (hSvc == NULL)
04312     {
04313         DPRINT1("Invalid service handle!\n");
04314         return ERROR_INVALID_HANDLE;
04315     }
04316 
04317     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
04318                                   SERVICE_START))
04319     {
04320         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
04321         return ERROR_ACCESS_DENIED;
04322     }
04323 
04324     lpService = hSvc->ServiceEntry;
04325     if (lpService == NULL)
04326     {
04327         DPRINT("lpService == NULL!\n");
04328         return ERROR_INVALID_HANDLE;
04329     }
04330 
04331     if (lpService->dwStartType == SERVICE_DISABLED)
04332         return ERROR_SERVICE_DISABLED;
04333 
04334     if (lpService->bDeleted)
04335         return ERROR_SERVICE_MARKED_FOR_DELETE;
04336 
04337     /* Build a Unicode argument vector */
04338     if (argc > 0)
04339     {
04340         lpVector = HeapAlloc(GetProcessHeap(),
04341                              HEAP_ZERO_MEMORY,
04342                              argc * sizeof(LPWSTR));
04343         if (lpVector == NULL)
04344             return ERROR_NOT_ENOUGH_MEMORY;
04345 
04346         for (i = 0; i < argc; i++)
04347         {
04348             dwLength = MultiByteToWideChar(CP_ACP,
04349                                            0,
04350                                            ((LPSTR*)argv)[i],
04351                                            -1,
04352                                            NULL,
04353                                            0);
04354 
04355             lpVector[i] = HeapAlloc(GetProcessHeap(),
04356                                     HEAP_ZERO_MEMORY,
04357                                     dwLength * sizeof(WCHAR));
04358             if (lpVector[i] == NULL)
04359             {
04360                 dwError = ERROR_NOT_ENOUGH_MEMORY;
04361                 goto done;
04362             }
04363 
04364             MultiByteToWideChar(CP_ACP,
04365                                 0,
04366                                 ((LPSTR*)argv)[i],
04367                                 -1,
04368                                 lpVector[i],
04369                                 dwLength);
04370         }
04371     }
04372 
04373     /* Start the service */
04374     dwError = ScmStartService(lpService, argc, lpVector);
04375 
04376 done:
04377     /* Free the Unicode argument vector */
04378     if (lpVector != NULL)
04379     {
04380         for (i = 0; i < argc; i++)
04381         {
04382             if (lpVector[i] != NULL)
04383                 HeapFree(GetProcessHeap(), 0, lpVector[i]);
04384         }
04385         HeapFree(GetProcessHeap(), 0, lpVector);
04386     }
04387 
04388     return dwError;
04389 }
04390 
04391 
04392 /* Function 32 */
04393 DWORD RGetServiceDisplayNameA(
04394     SC_RPC_HANDLE hSCManager,
04395     LPCSTR lpServiceName,
04396     LPSTR lpDisplayName,
04397     LPBOUNDED_DWORD_4K lpcchBuffer)
04398 {
04399 //    PMANAGER_HANDLE hManager;
04400     PSERVICE lpService = NULL;
04401     DWORD dwLength;
04402     DWORD dwError;
04403     LPWSTR lpServiceNameW;
04404 
04405     DPRINT("RGetServiceDisplayNameA() called\n");
04406     DPRINT("hSCManager = %p\n", hSCManager);
04407     DPRINT("lpServiceName: %s\n", lpServiceName);
04408     DPRINT("lpDisplayName: %p\n", lpDisplayName);
04409     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
04410 
04411 //    hManager = (PMANAGER_HANDLE)hSCManager;
04412 //    if (hManager->Handle.Tag != MANAGER_TAG)
04413 //    {
04414 //        DPRINT("Invalid manager handle!\n");
04415 //        return ERROR_INVALID_HANDLE;
04416 //    }
04417 
04418     if (lpServiceName != NULL)
04419     {
04420         dwLength = strlen(lpServiceName) + 1;
04421         lpServiceNameW = HeapAlloc(GetProcessHeap(),
04422                                    HEAP_ZERO_MEMORY,
04423                                    dwLength * sizeof(WCHAR));
04424         if (!lpServiceNameW)
04425             return ERROR_NOT_ENOUGH_MEMORY;
04426 
04427         MultiByteToWideChar(CP_ACP,
04428                             0,
04429                             lpServiceName,
04430                             -1,
04431                             lpServiceNameW,
04432                             dwLength);
04433 
04434         lpService = ScmGetServiceEntryByName(lpServiceNameW);
04435 
04436         HeapFree(GetProcessHeap(), 0, lpServiceNameW);
04437     }
04438 
04439     if (lpService == NULL)
04440     {
04441         DPRINT("Could not find a service!\n");
04442 
04443         /* If the service could not be found and lpcchBuffer is 0, windows
04444            puts null in lpDisplayName and puts 1 in lpcchBuffer */
04445         if (*lpcchBuffer == 0)
04446         {
04447             *lpcchBuffer = 1;
04448             if (lpDisplayName != NULL)
04449             {
04450                 *lpDisplayName = '\0';
04451             }
04452         }
04453         return ERROR_SERVICE_DOES_NOT_EXIST;
04454     }
04455 
04456     if (!lpService->lpDisplayName)
04457     {
04458         dwLength = wcslen(lpService->lpServiceName);
04459         if (lpDisplayName != NULL &&
04460             *lpcchBuffer > dwLength)
04461         {
04462             WideCharToMultiByte(CP_ACP,
04463                                 0,
04464                                 lpService->lpServiceName,
04465                                 wcslen(lpService->lpServiceName),
04466                                 lpDisplayName,
04467                                 dwLength + 1,
04468                                 NULL,
04469                                 NULL);
04470             return ERROR_SUCCESS;
04471         }
04472     }
04473     else
04474     {
04475         dwLength = wcslen(lpService->lpDisplayName);
04476         if (lpDisplayName != NULL &&
04477             *lpcchBuffer > dwLength)
04478         {
04479             WideCharToMultiByte(CP_ACP,
04480                                 0,
04481                                 lpService->lpDisplayName,
04482                                 wcslen(lpService->lpDisplayName),
04483                                 lpDisplayName,
04484                                 dwLength + 1,
04485                                 NULL,
04486                                 NULL);
04487             return ERROR_SUCCESS;
04488         }
04489     }
04490 
04491     dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
04492 
04493     *lpcchBuffer = dwLength * 2;
04494 
04495     return dwError;
04496 }
04497 
04498 
04499 /* Function 33 */
04500 DWORD RGetServiceKeyNameA(
04501     SC_RPC_HANDLE hSCManager,
04502     LPCSTR lpDisplayName,
04503     LPSTR lpServiceName,
04504     LPBOUNDED_DWORD_4K lpcchBuffer)
04505 {
04506     PSERVICE lpService;
04507     DWORD dwLength;
04508     DWORD dwError;
04509     LPWSTR lpDisplayNameW;
04510 
04511     DPRINT("RGetServiceKeyNameA() called\n");
04512     DPRINT("hSCManager = %p\n", hSCManager);
04513     DPRINT("lpDisplayName: %s\n", lpDisplayName);
04514     DPRINT("lpServiceName: %p\n", lpServiceName);
04515     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
04516 
04517     dwLength = strlen(lpDisplayName) + 1;
04518     lpDisplayNameW = HeapAlloc(GetProcessHeap(),
04519                                HEAP_ZERO_MEMORY,
04520                                dwLength * sizeof(WCHAR));
04521     if (!lpDisplayNameW)
04522         return ERROR_NOT_ENOUGH_MEMORY;
04523 
04524     MultiByteToWideChar(CP_ACP,
04525                         0,
04526                         lpDisplayName,
04527                         -1,
04528                         lpDisplayNameW,
04529                         dwLength);
04530 
04531     lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
04532 
04533     HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
04534 
04535     if (lpService == NULL)
04536     {
04537         DPRINT("Could not find the service!\n");
04538 
04539         /* If the service could not be found and lpcchBuffer is 0,
04540            put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
04541         if (*lpcchBuffer == 0)
04542         {
04543             *lpcchBuffer = 1;
04544             if (lpServiceName != NULL)
04545             {
04546                 *lpServiceName = '\0';
04547             }
04548         }
04549 
04550         return ERROR_SERVICE_DOES_NOT_EXIST;
04551     }
04552 
04553     dwLength = wcslen(lpService->lpServiceName);
04554     if (lpServiceName != NULL &&
04555         *lpcchBuffer > dwLength)
04556     {
04557         WideCharToMultiByte(CP_ACP,
04558                             0,
04559                             lpService->lpServiceName,
04560                             wcslen(lpService->lpServiceName),
04561                             lpServiceName,
04562                             dwLength + 1,
04563                             NULL,
04564                             NULL);
04565         return ERROR_SUCCESS;
04566     }
04567 
04568     dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
04569 
04570     *lpcchBuffer = dwLength * 2;
04571 
04572     return dwError;
04573 }
04574 
04575 
04576 /* Function 34 */
04577 DWORD RI_ScGetCurrentGroupStateW(
04578     SC_RPC_HANDLE hSCManager,
04579     LPWSTR lpLoadOrderGroup,
04580     LPDWORD lpState)
04581 {
04582     UNIMPLEMENTED;
04583     return ERROR_CALL_NOT_IMPLEMENTED;
04584 }
04585 
04586 
04587 /* Function 35 */
04588 DWORD REnumServiceGroupW(
04589     SC_RPC_HANDLE hSCManager,
04590     DWORD dwServiceType,
04591     DWORD dwServiceState,
04592     LPBYTE lpBuffer,
04593     DWORD cbBufSize,
04594     LPBOUNDED_DWORD_256K pcbBytesNeeded,
04595     LPBOUNDED_DWORD_256K lpServicesReturned,
04596     LPBOUNDED_DWORD_256K lpResumeIndex,
04597     LPCWSTR pszGroupName)
04598 {
04599     UNIMPLEMENTED;
04600     return ERROR_CALL_NOT_IMPLEMENTED;
04601 }
04602 
04603 
04604 //
04605 // WARNING: This function is untested
04606 //
04607 /* Function 36 */
04608 DWORD RChangeServiceConfig2A(
04609     SC_RPC_HANDLE hService,
04610     SC_RPC_CONFIG_INFOA Info)
04611 {
04612     SC_RPC_CONFIG_INFOW InfoW;
04613     DWORD dwRet, dwLength;
04614     PVOID ptr = NULL;
04615 
04616     DPRINT("RChangeServiceConfig2A() called\n");
04617     DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
04618 
04619     InfoW.dwInfoLevel = Info.dwInfoLevel;
04620 
04621     if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
04622     {
04623         LPSERVICE_DESCRIPTIONW lpServiceDescriptonW;
04624         //LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
04625 
04626         //lpServiceDescriptonA = Info.psd;
04627 
04631             dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR);
04632 
04633             lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
04634                                              0,
04635                                              dwLength + sizeof(SERVICE_DESCRIPTIONW));
04636             if (!lpServiceDescriptonW)
04637             {
04638                 return ERROR_NOT_ENOUGH_MEMORY;
04639             }
04640 
04641             lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1);
04642 
04643             MultiByteToWideChar(CP_ACP,
04644                                 0,
04645                                 Info.lpDescription,
04646                                 -1,
04647                                 lpServiceDescriptonW->lpDescription,
04648                                 dwLength);
04649 
04650             ptr = lpServiceDescriptonW;
04651             InfoW.psd = lpServiceDescriptonW;
04653     }
04654     else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
04655     {
04656         LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
04657         LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
04658         DWORD dwRebootLen = 0;
04659         DWORD dwCommandLen = 0;
04660 
04661         lpServiceFailureActionsA = Info.psfa;
04662 
04663         if (lpServiceFailureActionsA)
04664         {
04665             if (lpServiceFailureActionsA->lpRebootMsg)
04666             {
04667                 dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR);
04668             }
04669             if (lpServiceFailureActionsA->lpCommand)
04670             {
04671                 dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR);
04672             }
04673             dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
04674 
04675             lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
04676                                                  0,
04677                                                  dwLength);
04678             if (!lpServiceFailureActionsW)
04679             {
04680                 return ERROR_NOT_ENOUGH_MEMORY;
04681             }
04682 
04683             lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
04684             lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
04685             CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
04686 
04687             if (lpServiceFailureActionsA->lpRebootMsg)
04688             {
04689                 MultiByteToWideChar(CP_ACP,
04690                                     0,
04691                                     lpServiceFailureActionsA->lpRebootMsg,
04692                                     -1,
04693                                     lpServiceFailureActionsW->lpRebootMsg,
04694                                     dwRebootLen);
04695             }
04696 
04697             if (lpServiceFailureActionsA->lpCommand)
04698             {
04699                 MultiByteToWideChar(CP_ACP,
04700                                     0,
04701                                     lpServiceFailureActionsA->lpCommand,
04702                                     -1,
04703                                     lpServiceFailureActionsW->lpCommand,
04704                                     dwCommandLen);
04705             }
04706 
04707             ptr = lpServiceFailureActionsW;
04708         }
04709     }
04710 
04711     dwRet = RChangeServiceConfig2W(hService, InfoW);
04712 
04713     HeapFree(GetProcessHeap(), 0, ptr);
04714 
04715     return dwRet;
04716 }
04717 
04718 
04719 /* Function 37 */
04720 DWORD RChangeServiceConfig2W(
04721     SC_RPC_HANDLE hService,
04722     SC_RPC_CONFIG_INFOW Info)
04723 {
04724     DWORD dwError = ERROR_SUCCESS;
04725     PSERVICE_HANDLE hSvc;
04726     PSERVICE lpService = NULL;
04727     HKEY hServiceKey = NULL;
04728 
04729     DPRINT("RChangeServiceConfig2W() called\n");
04730     DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
04731 
04732     if (ScmShutdown)
04733         return ERROR_SHUTDOWN_IN_PROGRESS;
04734 
04735     hSvc = ScmGetServiceFromHandle(hService);
04736     if (hSvc == NULL)
04737     {
04738         DPRINT1("Invalid service handle!\n");
04739         return ERROR_INVALID_HANDLE;
04740     }
04741 
04742     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
04743                                   SERVICE_CHANGE_CONFIG))
04744     {
04745         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
04746         return ERROR_ACCESS_DENIED;
04747     }
04748 
04749     lpService = hSvc->ServiceEntry;
04750     if (lpService == NULL)
04751     {
04752         DPRINT("lpService == NULL!\n");
04753         return ERROR_INVALID_HANDLE;
04754     }
04755 
04756     /* Lock the service database exclusively */
04757     ScmLockDatabaseExclusive();
04758 
04759     if (lpService->bDeleted)
04760     {
04761         DPRINT("The service has already been marked for delete!\n");
04762         dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
04763         goto done;
04764     }
04765 
04766     /* Open the service key */
04767     dwError = ScmOpenServiceKey(lpService->szServiceName,
04768                                 KEY_SET_VALUE,
04769                                 &hServiceKey);
04770     if (dwError != ERROR_SUCCESS)
04771         goto done;
04772 
04773     if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
04774     {
04775         LPSERVICE_DESCRIPTIONW lpServiceDescription;
04776 
04777         lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
04778 
04779         if (lpServiceDescription != NULL &&
04780             lpServiceDescription->lpDescription != NULL)
04781         {
04782             DPRINT("Setting value %S\n", lpServiceDescription->lpDescription);
04783             dwError = RegSetValueExW(hServiceKey,
04784                                      L"Description",
04785                                      0,
04786                                      REG_SZ,
04787                                      (LPBYTE)lpServiceDescription->lpDescription,
04788                                      (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR));
04789             if (dwError != ERROR_SUCCESS)
04790                 goto done;
04791         }
04792     }
04793     else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
04794     {
04795         UNIMPLEMENTED;
04796         dwError = ERROR_CALL_NOT_IMPLEMENTED;
04797         goto done;
04798     }
04799 
04800 done:
04801     /* Unlock the service database */
04802     ScmUnlockDatabase();
04803 
04804     if (hServiceKey != NULL)
04805         RegCloseKey(hServiceKey);
04806 
04807     DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
04808 
04809     return dwError;
04810 }
04811 
04812 
04813 /* Function 38 */
04814 DWORD RQueryServiceConfig2A(
04815     SC_RPC_HANDLE hService,
04816     DWORD dwInfoLevel,
04817     LPBYTE lpBuffer,
04818     DWORD cbBufSize,
04819     LPBOUNDED_DWORD_8K pcbBytesNeeded)
04820 {
04821     DWORD dwError = ERROR_SUCCESS;
04822     PSERVICE_HANDLE hSvc;
04823     PSERVICE lpService = NULL;
04824     HKEY hServiceKey = NULL;
04825     LPWSTR lpDescriptionW = NULL;
04826 
04827     DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
04828            hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
04829 
04830     if (!lpBuffer)
04831         return ERROR_INVALID_ADDRESS;
04832 
04833     if (ScmShutdown)
04834         return ERROR_SHUTDOWN_IN_PROGRESS;
04835 
04836     hSvc = ScmGetServiceFromHandle(hService);
04837     if (hSvc == NULL)
04838     {
04839         DPRINT1("Invalid service handle!\n");
04840         return ERROR_INVALID_HANDLE;
04841     }
04842 
04843     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
04844                                   SERVICE_QUERY_CONFIG))
04845     {
04846         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
04847         return ERROR_ACCESS_DENIED;
04848     }
04849 
04850     lpService = hSvc->ServiceEntry;
04851     if (lpService == NULL)
04852     {
04853         DPRINT("lpService == NULL!\n");
04854         return ERROR_INVALID_HANDLE;
04855     }
04856 
04857     /* Lock the service database shared */
04858     ScmLockDatabaseShared();
04859 
04860     dwError = ScmOpenServiceKey(lpService->lpServiceName,
04861                                 KEY_READ,
04862                                 &hServiceKey);
04863     if (dwError != ERROR_SUCCESS)
04864         goto done;
04865 
04866     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
04867     {
04868         LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
04869         LPSTR lpStr;
04870 
04871         dwError = ScmReadString(hServiceKey,
04872                                 L"Description",
04873                                 &lpDescriptionW);
04874         if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
04875             goto done;
04876 
04877         *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
04878         if (dwError == ERROR_SUCCESS)
04879             *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
04880 
04881         if (cbBufSize < *pcbBytesNeeded)
04882         {
04883             dwError = ERROR_INSUFFICIENT_BUFFER;
04884             goto done;
04885         }
04886 
04887         if (dwError == ERROR_SUCCESS)
04888         {
04889             lpStr = (LPSTR)(lpServiceDescription + 1);
04890 
04891             WideCharToMultiByte(CP_ACP,
04892                                 0,
04893                                 lpDescriptionW,
04894                                 -1,
04895                                 lpStr,
04896                                 wcslen(lpDescriptionW),
04897                                 NULL,
04898                                 NULL);
04899             lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
04900         }
04901         else
04902         {
04903             lpServiceDescription->lpDescription = NULL;
04904             dwError = ERROR_SUCCESS;
04905             goto done;
04906         }
04907     }
04908     else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
04909     {
04910         UNIMPLEMENTED;
04911         dwError = ERROR_CALL_NOT_IMPLEMENTED;
04912         goto done;
04913     }
04914 
04915 done:
04916     /* Unlock the service database */
04917     ScmUnlockDatabase();
04918 
04919     if (lpDescriptionW != NULL)
04920         HeapFree(GetProcessHeap(), 0, lpDescriptionW);
04921 
04922     if (hServiceKey != NULL)
04923         RegCloseKey(hServiceKey);
04924 
04925     DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
04926 
04927     return dwError;
04928 }
04929 
04930 
04931 /* Function 39 */
04932 DWORD RQueryServiceConfig2W(
04933     SC_RPC_HANDLE hService,
04934     DWORD dwInfoLevel,
04935     LPBYTE lpBuffer,
04936     DWORD cbBufSize,
04937     LPBOUNDED_DWORD_8K pcbBytesNeeded)
04938 {
04939     DWORD dwError = ERROR_SUCCESS;
04940     PSERVICE_HANDLE hSvc;
04941     PSERVICE lpService = NULL;
04942     HKEY hServiceKey = NULL;
04943     DWORD dwRequiredSize;
04944     LPWSTR lpDescription = NULL;
04945     LPWSTR lpFailureCommand = NULL;
04946     LPWSTR lpRebootMessage = NULL;
04947 
04948     DPRINT("RQueryServiceConfig2W() called\n");
04949 
04950     if (!lpBuffer)
04951         return ERROR_INVALID_ADDRESS;
04952 
04953     if (ScmShutdown)
04954         return ERROR_SHUTDOWN_IN_PROGRESS;
04955 
04956     hSvc = ScmGetServiceFromHandle(hService);
04957     if (hSvc == NULL)
04958     {
04959         DPRINT1("Invalid service handle!\n");
04960         return ERROR_INVALID_HANDLE;
04961     }
04962 
04963     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
04964                                   SERVICE_QUERY_CONFIG))
04965     {
04966         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
04967         return ERROR_ACCESS_DENIED;
04968     }
04969 
04970     lpService = hSvc->ServiceEntry;
04971     if (lpService == NULL)
04972     {
04973         DPRINT("lpService == NULL!\n");
04974         return ERROR_INVALID_HANDLE;
04975     }
04976 
04977     /* Lock the service database shared */
04978     ScmLockDatabaseShared();
04979 
04980     dwError = ScmOpenServiceKey(lpService->lpServiceName,
04981                                 KEY_READ,
04982                                 &hServiceKey);
04983     if (dwError != ERROR_SUCCESS)
04984         goto done;
04985 
04986     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
04987     {
04988         LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
04989         LPWSTR lpStr;
04990 
04991         dwError = ScmReadString(hServiceKey,
04992                                 L"Description",
04993                                 &lpDescription);
04994         if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
04995             goto done;
04996 
04997         *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW);
04998         if (dwError == ERROR_SUCCESS)
04999             *pcbBytesNeeded += ((wcslen(lpDescription) + 1) * sizeof(WCHAR));
05000 
05001         if (cbBufSize < *pcbBytesNeeded)
05002         {
05003             dwError = ERROR_INSUFFICIENT_BUFFER;
05004             goto done;
05005         }
05006 
05007         if (dwError == ERROR_SUCCESS)
05008         {
05009             lpStr = (LPWSTR)(lpServiceDescription + 1);
05010             wcscpy(lpStr, lpDescription);
05011             lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
05012         }
05013         else
05014         {
05015             lpServiceDescription->lpDescription = NULL;
05016             dwError = ERROR_SUCCESS;
05017         }
05018     }
05019     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
05020     {
05021         LPWSTR lpStr;
05022         LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
05023 
05024         UNIMPLEMENTED;
05025 
05026         dwError = ScmReadString(hServiceKey,
05027                                 L"FailureCommand",
05028                                 &lpFailureCommand);
05029 
05030         dwError = ScmReadString(hServiceKey,
05031                                 L"RebootMessage",
05032                                 &lpRebootMessage);
05033 
05034         dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
05035 
05036         if (lpFailureCommand)
05037             dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR);
05038 
05039         if (lpRebootMessage)
05040             dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR);
05041 
05042         if (cbBufSize < dwRequiredSize)
05043         {
05044             *pcbBytesNeeded = dwRequiredSize;
05045             dwError = ERROR_INSUFFICIENT_BUFFER;
05046             goto done;
05047         }
05048 
05049         lpFailureActions->cActions = 0;
05050         lpFailureActions->dwResetPeriod = 0;
05051         lpFailureActions->lpCommand = NULL;
05052         lpFailureActions->lpRebootMsg = NULL;
05053         lpFailureActions->lpsaActions = NULL;
05054 
05055         lpStr = (LPWSTR)(lpFailureActions + 1);
05056         if (lpRebootMessage)
05057         {
05058             wcscpy(lpStr, lpRebootMessage);
05059             lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage);
05060             lpStr += wcslen(lpRebootMessage) + 1;
05061         }
05062 
05063         if (lpFailureCommand)
05064         {
05065             wcscpy(lpStr, lpFailureCommand);
05066             lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand);
05067             lpStr += wcslen(lpRebootMessage) + 1;
05068         }
05069         dwError = STATUS_SUCCESS;
05070         goto done;
05071     }
05072 
05073 done:
05074     /* Unlock the service database */
05075     ScmUnlockDatabase();
05076 
05077     if (lpDescription != NULL)
05078         HeapFree(GetProcessHeap(), 0, lpDescription);
05079 
05080     if (lpRebootMessage != NULL)
05081         HeapFree(GetProcessHeap(), 0, lpRebootMessage);
05082 
05083     if (lpFailureCommand != NULL)
05084         HeapFree(GetProcessHeap(), 0, lpFailureCommand);
05085 
05086     if (hServiceKey != NULL)
05087         RegCloseKey(hServiceKey);
05088 
05089     DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
05090 
05091     return dwError;
05092 }
05093 
05094 
05095 /* Function 40 */
05096 DWORD RQueryServiceStatusEx(
05097     SC_RPC_HANDLE hService,
05098     SC_STATUS_TYPE InfoLevel,
05099     LPBYTE lpBuffer,
05100     DWORD cbBufSize,
05101     LPBOUNDED_DWORD_8K pcbBytesNeeded)
05102 {
05103     LPSERVICE_STATUS_PROCESS lpStatus;
05104     PSERVICE_HANDLE hSvc;
05105     PSERVICE lpService;
05106 
05107     DPRINT("RQueryServiceStatusEx() called\n");
05108 
05109     if (ScmShutdown)
05110         return ERROR_SHUTDOWN_IN_PROGRESS;
05111 
05112     if (InfoLevel != SC_STATUS_PROCESS_INFO)
05113         return ERROR_INVALID_LEVEL;
05114 
05115     *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
05116 
05117     if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
05118         return ERROR_INSUFFICIENT_BUFFER;
05119 
05120     hSvc = ScmGetServiceFromHandle(hService);
05121     if (hSvc == NULL)
05122     {
05123         DPRINT1("Invalid service handle!\n");
05124         return ERROR_INVALID_HANDLE;
05125     }
05126 
05127     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
05128                                   SERVICE_QUERY_STATUS))
05129     {
05130         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
05131         return ERROR_ACCESS_DENIED;
05132     }
05133 
05134     lpService = hSvc->ServiceEntry;
05135     if (lpService == NULL)
05136     {
05137         DPRINT("lpService == NULL!\n");
05138         return ERROR_INVALID_HANDLE;
05139     }
05140 
05141     /* Lock the service database shared */
05142     ScmLockDatabaseShared();
05143 
05144     lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
05145 
05146     /* Return service status information */
05147     RtlCopyMemory(lpStatus,
05148                   &lpService->Status,
05149                   sizeof(SERVICE_STATUS));
05150 
05151     lpStatus->dwProcessId = (lpService->lpImage != NULL) ? lpService->lpImage->dwProcessId : 0; /* FIXME */
05152     lpStatus->dwServiceFlags = 0;           /* FIXME */
05153 
05154     /* Unlock the service database */
05155     ScmUnlockDatabase();
05156 
05157     return ERROR_SUCCESS;
05158 }
05159 
05160 
05161 /* Function 41 */
05162 DWORD REnumServicesStatusExA(
05163     SC_RPC_HANDLE hSCManager,
05164     SC_ENUM_TYPE InfoLevel,
05165     DWORD dwServiceType,
05166     DWORD dwServiceState,
05167     LPBYTE lpBuffer,
05168     DWORD cbBufSize,
05169     LPBOUNDED_DWORD_256K pcbBytesNeeded,
05170     LPBOUNDED_DWORD_256K lpServicesReturned,
05171     LPBOUNDED_DWORD_256K lpResumeIndex,
05172     LPCSTR pszGroupName)
05173 {
05174     LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
05175     LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
05176     LPWSTR lpStringPtrW;
05177     LPSTR lpStringPtrA;
05178     LPWSTR pszGroupNameW = NULL;
05179     DWORD dwError;
05180     DWORD dwServiceCount;
05181 
05182     DPRINT("REnumServicesStatusExA() called\n");
05183 
05184     if (pszGroupName)
05185     {
05186         pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
05187         if (!pszGroupNameW)
05188         {
05189              DPRINT("Failed to allocate buffer!\n");
05190              return ERROR_NOT_ENOUGH_MEMORY;
05191         }
05192 
05193         MultiByteToWideChar(CP_ACP,
05194                             0,
05195                             pszGroupName,
05196                             -1,
05197                             pszGroupNameW,
05198                             strlen(pszGroupName) + 1);
05199     }
05200 
05201     if ((cbBufSize > 0) && (lpBuffer))
05202     {
05203         lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
05204         if (!lpStatusPtrW)
05205         {
05206             DPRINT("Failed to allocate buffer!\n");
05207             return ERROR_NOT_ENOUGH_MEMORY;
05208         }
05209     }
05210 
05211     dwError = REnumServicesStatusExW(hSCManager,
05212                                      InfoLevel,
05213                                      dwServiceType,
05214                                      dwServiceState,
05215                                      (LPBYTE)lpStatusPtrW,
05216                                      cbBufSize,
05217                                      pcbBytesNeeded,
05218                                      lpServicesReturned,
05219                                      lpResumeIndex,
05220                                      pszGroupNameW);
05221 
05222     /* if no services were returned then we are Done */
05223     if (*lpServicesReturned == 0)
05224         goto Done;
05225 
05226     lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
05227     lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
05228                   *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
05229     lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
05230                   *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
05231 
05232     for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
05233     {
05234         /* Copy the service name */
05235         WideCharToMultiByte(CP_ACP,
05236                             0,
05237                             lpStringPtrW,
05238                             -1,
05239                             lpStringPtrA,
05240                             wcslen(lpStringPtrW),
05241                             0,
05242                             0);
05243 
05244         lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
05245         lpStringPtrA += wcslen(lpStringPtrW) + 1;
05246         lpStringPtrW += wcslen(lpStringPtrW) + 1;
05247 
05248         /* Copy the display name */
05249         WideCharToMultiByte(CP_ACP,
05250                             0,
05251                             lpStringPtrW,
05252                             -1,
05253                             lpStringPtrA,
05254                             wcslen(lpStringPtrW),
05255                             0,
05256                             0);
05257 
05258         lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
05259         lpStringPtrA += wcslen(lpStringPtrW) + 1;
05260         lpStringPtrW += wcslen(lpStringPtrW) + 1;
05261 
05262         /* Copy the status information */
05263         memcpy(&lpStatusPtrA->ServiceStatusProcess,
05264                &lpStatusPtrW->ServiceStatusProcess,
05265                sizeof(SERVICE_STATUS));
05266 
05267         lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */
05268         lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
05269         lpStatusPtrA++;
05270     }
05271 
05272 Done:;
05273     if (pszGroupNameW)
05274         HeapFree(GetProcessHeap(), 0, pszGroupNameW);
05275 
05276     if (lpStatusPtrW)
05277         HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
05278 
05279     DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
05280 
05281     return dwError;
05282 }
05283 
05284 
05285 /* Function 42 */
05286 DWORD REnumServicesStatusExW(
05287     SC_RPC_HANDLE hSCManager,
05288     SC_ENUM_TYPE InfoLevel,
05289     DWORD dwServiceType,
05290     DWORD dwServiceState,
05291     LPBYTE lpBuffer,
05292     DWORD cbBufSize,
05293     LPBOUNDED_DWORD_256K pcbBytesNeeded,
05294     LPBOUNDED_DWORD_256K lpServicesReturned,
05295     LPBOUNDED_DWORD_256K lpResumeIndex,
05296     LPCWSTR pszGroupName)
05297 {
05298     PMANAGER_HANDLE hManager;
05299     PSERVICE lpService;
05300     DWORD dwError = ERROR_SUCCESS;
05301     PLIST_ENTRY ServiceEntry;
05302     PSERVICE CurrentService;
05303     DWORD dwState;
05304     DWORD dwRequiredSize;
05305     DWORD dwServiceCount;
05306     DWORD dwSize;
05307     DWORD dwLastResumeCount = 0;
05308     LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
05309     LPWSTR lpStringPtr;
05310 
05311     DPRINT("REnumServicesStatusExW() called\n");
05312 
05313     if (ScmShutdown)
05314         return ERROR_SHUTDOWN_IN_PROGRESS;
05315 
05316     if (InfoLevel != SC_ENUM_PROCESS_INFO)
05317         return ERROR_INVALID_LEVEL;
05318 
05319     hManager = ScmGetServiceManagerFromHandle(hSCManager);
05320     if (hManager == NULL)
05321     {
05322         DPRINT1("Invalid service manager handle!\n");
05323         return ERROR_INVALID_HANDLE;
05324     }
05325 
05326     *pcbBytesNeeded = 0;
05327     *lpServicesReturned = 0;
05328 
05329     if ((dwServiceType == 0) ||
05330         ((dwServiceType & ~(SERVICE_DRIVER | SERVICE_WIN32)) != 0))
05331     {
05332         DPRINT("Not a valid Service Type!\n");
05333         return ERROR_INVALID_PARAMETER;
05334     }
05335 
05336     if ((dwServiceState != SERVICE_ACTIVE) &&
05337         (dwServiceState != SERVICE_INACTIVE) &&
05338         (dwServiceState != SERVICE_STATE_ALL))
05339     {
05340         DPRINT("Not a valid Service State!\n");
05341         return ERROR_INVALID_PARAMETER;
05342     }
05343 
05344     /* Check access rights */
05345     if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
05346                                   SC_MANAGER_ENUMERATE_SERVICE))
05347     {
05348         DPRINT("Insufficient access rights! 0x%lx\n",
05349                hManager->Handle.DesiredAccess);
05350         return ERROR_ACCESS_DENIED;
05351     }
05352 
05353     if (lpResumeIndex)
05354         dwLastResumeCount = *lpResumeIndex;
05355 
05356     /* Lock the service database shared */
05357     ScmLockDatabaseShared();
05358 
05359     lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
05360     if (lpService == NULL)
05361     {
05362         dwError = ERROR_SUCCESS;
05363         goto Done;
05364     }
05365 
05366     dwRequiredSize = 0;
05367     dwServiceCount = 0;
05368 
05369     for (ServiceEntry = &lpService->ServiceListEntry;
05370          ServiceEntry != &ServiceListHead;
05371          ServiceEntry = ServiceEntry->Flink)
05372     {
05373         CurrentService = CONTAINING_RECORD(ServiceEntry,
05374                                            SERVICE,
05375                                            ServiceListEntry);
05376 
05377         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
05378             continue;
05379 
05380         dwState = SERVICE_ACTIVE;
05381         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
05382             dwState = SERVICE_INACTIVE;
05383 
05384         if ((dwState & dwServiceState) == 0)
05385             continue;
05386 
05387         if (pszGroupName)
05388         {
05389             if (*pszGroupName == 0)
05390             {
05391                 if (CurrentService->lpGroup != NULL)
05392                     continue;
05393             }
05394             else
05395             {
05396                 if ((CurrentService->lpGroup == NULL) ||
05397                     _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
05398                     continue;
05399             }
05400         }
05401 
05402         dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
05403                  ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
05404                  ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
05405 
05406         if (dwRequiredSize + dwSize <= cbBufSize)
05407         {
05408             DPRINT("Service name: %S  fit\n", CurrentService->lpServiceName);
05409             dwRequiredSize += dwSize;
05410             dwServiceCount++;
05411             dwLastResumeCount = CurrentService->dwResumeCount;
05412         }
05413         else
05414         {
05415             DPRINT("Service name: %S  no fit\n", CurrentService->lpServiceName);
05416             break;
05417         }
05418 
05419     }
05420 
05421     DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
05422     DPRINT("dwServiceCount: %lu\n", dwServiceCount);
05423 
05424     for (;
05425          ServiceEntry != &ServiceListHead;
05426          ServiceEntry = ServiceEntry->Flink)
05427     {
05428         CurrentService = CONTAINING_RECORD(ServiceEntry,
05429                                            SERVICE,
05430                                            ServiceListEntry);
05431 
05432         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
05433             continue;
05434 
05435         dwState = SERVICE_ACTIVE;
05436         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
05437             dwState = SERVICE_INACTIVE;
05438 
05439         if ((dwState & dwServiceState) == 0)
05440             continue;
05441 
05442         if (pszGroupName)
05443         {
05444             if (*pszGroupName == 0)
05445             {
05446                 if (CurrentService->lpGroup != NULL)
05447                     continue;
05448             }
05449             else
05450             {
05451                 if ((CurrentService->lpGroup == NULL) ||
05452                     _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
05453                     continue;
05454             }
05455         }
05456 
05457         dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
05458                            ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
05459                            ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
05460 
05461         dwError = ERROR_MORE_DATA;
05462     }
05463 
05464     DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
05465 
05466     if (lpResumeIndex)
05467         *lpResumeIndex = dwLastResumeCount;
05468 
05469     *lpServicesReturned = dwServiceCount;
05470     *pcbBytesNeeded = dwRequiredSize;
05471 
05472     /* If there was no services that matched */
05473     if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
05474     {
05475         dwError = ERROR_SERVICE_DOES_NOT_EXIST;
05476         goto Done;
05477     }
05478 
05479     lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
05480     lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
05481                            dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
05482 
05483     dwRequiredSize = 0;
05484     for (ServiceEntry = &lpService->ServiceListEntry;
05485          ServiceEntry != &ServiceListHead;
05486          ServiceEntry = ServiceEntry->Flink)
05487     {
05488         CurrentService = CONTAINING_RECORD(ServiceEntry,
05489                                            SERVICE,
05490                                            ServiceListEntry);
05491 
05492         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
05493             continue;
05494 
05495         dwState = SERVICE_ACTIVE;
05496         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
05497             dwState = SERVICE_INACTIVE;
05498 
05499         if ((dwState & dwServiceState) == 0)
05500             continue;
05501 
05502         if (pszGroupName)
05503         {
05504             if (*pszGroupName == 0)
05505             {
05506                 if (CurrentService->lpGroup != NULL)
05507                     continue;
05508             }
05509             else
05510             {
05511                 if ((CurrentService->lpGroup == NULL) ||
05512                     _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
05513                     continue;
05514             }
05515         }
05516 
05517         dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
05518                  ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
05519                  ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
05520 
05521         if (dwRequiredSize + dwSize <= cbBufSize)
05522         {
05523             /* Copy the service name */
05524             wcscpy(lpStringPtr,
05525                    CurrentService->lpServiceName);
05526             lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
05527             lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
05528 
05529             /* Copy the display name */
05530             wcscpy(lpStringPtr,
05531                    CurrentService->lpDisplayName);
05532             lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
05533             lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
05534 
05535             /* Copy the status information */
05536             memcpy(&lpStatusPtr->ServiceStatusProcess,
05537                    &CurrentService->Status,
05538                    sizeof(SERVICE_STATUS));
05539             lpStatusPtr->ServiceStatusProcess.dwProcessId =
05540                 (CurrentService->lpImage != NULL) ? CurrentService->lpImage->dwProcessId : 0; /* FIXME */
05541             lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
05542 
05543             lpStatusPtr++;
05544             dwRequiredSize += dwSize;
05545         }
05546         else
05547         {
05548             break;
05549         }
05550     }
05551 
05552     if (dwError == 0)
05553     {
05554         *pcbBytesNeeded = 0;
05555         if (lpResumeIndex)
05556             *lpResumeIndex = 0;
05557     }
05558 
05559 Done:;
05560     /* Unlock the service database */
05561     ScmUnlockDatabase();
05562 
05563     DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
05564 
05565     return dwError;
05566 }
05567 
05568 
05569 /* Function 43 */
05570 DWORD RSendTSMessage(
05571     handle_t BindingHandle)  /* FIXME */
05572 {
05573     UNIMPLEMENTED;
05574     return ERROR_CALL_NOT_IMPLEMENTED;
05575 }
05576 
05577 
05578 /* Function 44 */
05579 DWORD RCreateServiceWOW64A(
05580     handle_t BindingHandle,
05581     LPSTR lpServiceName,
05582     LPSTR lpDisplayName,
05583     DWORD dwDesiredAccess,
05584     DWORD dwServiceType,
05585     DWORD dwStartType,
05586     DWORD dwErrorControl,
05587     LPSTR lpBinaryPathName,
05588     LPSTR lpLoadOrderGroup,
05589     LPDWORD lpdwTagId,
05590     LPBYTE lpDependencies,
05591     DWORD dwDependSize,
05592     LPSTR lpServiceStartName,
05593     LPBYTE lpPassword,
05594     DWORD dwPwSize,
05595     LPSC_RPC_HANDLE lpServiceHandle)
05596 {
05597     UNIMPLEMENTED;
05598     return ERROR_CALL_NOT_IMPLEMENTED;
05599 }
05600 
05601 
05602 /* Function 45 */
05603 DWORD RCreateServiceWOW64W(
05604     handle_t BindingHandle,
05605     LPWSTR lpServiceName,
05606     LPWSTR lpDisplayName,
05607     DWORD dwDesiredAccess,
05608     DWORD dwServiceType,
05609     DWORD dwStartType,
05610     DWORD dwErrorControl,
05611     LPWSTR lpBinaryPathName,
05612     LPWSTR lpLoadOrderGroup,
05613     LPDWORD lpdwTagId,
05614     LPBYTE lpDependencies,
05615     DWORD dwDependSize,
05616     LPWSTR lpServiceStartName,
05617     LPBYTE lpPassword,
05618     DWORD dwPwSize,
05619     LPSC_RPC_HANDLE lpServiceHandle)
05620 {
05621     UNIMPLEMENTED;
05622     return ERROR_CALL_NOT_IMPLEMENTED;
05623 }
05624 
05625 
05626 /* Function 46 */
05627 DWORD RQueryServiceTagInfo(
05628     handle_t BindingHandle)  /* FIXME */
05629 {
05630     UNIMPLEMENTED;
05631     return ERROR_CALL_NOT_IMPLEMENTED;
05632 }
05633 
05634 
05635 /* Function 47 */
05636 DWORD RNotifyServiceStatusChange(
05637     SC_RPC_HANDLE hService,
05638     SC_RPC_NOTIFY_PARAMS NotifyParams,
05639     GUID *pClientProcessGuid,
05640     GUID *pSCMProcessGuid,
05641     PBOOL pfCreateRemoteQueue,
05642     LPSC_NOTIFY_RPC_HANDLE phNotify)
05643 {
05644     UNIMPLEMENTED;
05645     return ERROR_CALL_NOT_IMPLEMENTED;
05646 }
05647 
05648 
05649 /* Function 48 */
05650 DWORD RGetNotifyResults(
05651     SC_NOTIFY_RPC_HANDLE hNotify,
05652     PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
05653 {
05654     UNIMPLEMENTED;
05655     return ERROR_CALL_NOT_IMPLEMENTED;
05656 }
05657 
05658 
05659 /* Function 49 */
05660 DWORD RCloseNotifyHandle(
05661     LPSC_NOTIFY_RPC_HANDLE phNotify,
05662     PBOOL pfApcFired)
05663 {
05664     UNIMPLEMENTED;
05665     return ERROR_CALL_NOT_IMPLEMENTED;
05666 }
05667 
05668 
05669 /* Function 50 */
05670 DWORD RControlServiceExA(
05671     SC_RPC_HANDLE hService,
05672     DWORD dwControl,
05673     DWORD dwInfoLevel)
05674 {
05675     UNIMPLEMENTED;
05676     return ERROR_CALL_NOT_IMPLEMENTED;
05677 }
05678 
05679 
05680 /* Function 51 */
05681 DWORD RControlServiceExW(
05682     SC_RPC_HANDLE hService,
05683     DWORD dwControl,
05684     DWORD dwInfoLevel)
05685 {
05686     UNIMPLEMENTED;
05687     return ERROR_CALL_NOT_IMPLEMENTED;
05688 }
05689 
05690 
05691 /* Function 52 */
05692 DWORD RSendPnPMessage(
05693     handle_t BindingHandle)  /* FIXME */
05694 {
05695     UNIMPLEMENTED;
05696     return ERROR_CALL_NOT_IMPLEMENTED;
05697 }
05698 
05699 
05700 /* Function 53 */
05701 DWORD RValidatePnPService(
05702     handle_t BindingHandle)  /* FIXME */
05703 {
05704     UNIMPLEMENTED;
05705     return ERROR_CALL_NOT_IMPLEMENTED;
05706 }
05707 
05708 
05709 /* Function 54 */
05710 DWORD ROpenServiceStatusHandle(
05711     handle_t BindingHandle)  /* FIXME */
05712 {
05713     UNIMPLEMENTED;
05714     return ERROR_CALL_NOT_IMPLEMENTED;
05715 }
05716 
05717 
05718 /* Function 55 */
05719 DWORD RFunction55(
05720     handle_t BindingHandle)  /* FIXME */
05721 {
05722     UNIMPLEMENTED;
05723     return ERROR_CALL_NOT_IMPLEMENTED;
05724 }
05725 
05726 
05727 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
05728 {
05729     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
05730 }
05731 
05732 
05733 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
05734 {
05735     HeapFree(GetProcessHeap(), 0, ptr);
05736 }
05737 
05738 
05739 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
05740 {
05741 }
05742 
05743 
05744 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
05745 {
05746 }
05747 
05748 
05749 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
05750 {
05751 }
05752 
05753 /* EOF */

Generated on Sun May 27 2012 04:17:56 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.