Use the service contol pipe to send a start command in order to start a service thread.
Added: trunk/reactos/include/services/
Added: trunk/reactos/include/services/services.h
Modified: trunk/reactos/lib/advapi32/service/sctrl.c
Modified: trunk/reactos/subsys/system/services/database.c

Added: trunk/reactos/include/services/services.h
--- trunk/reactos/include/services/services.h	2005-01-28 12:12:42 UTC (rev 13349)
+++ trunk/reactos/include/services/services.h	2005-01-28 13:28:56 UTC (rev 13350)
@@ -0,0 +1,24 @@
+/* $Id$
+ *
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS kernel
+ * FILE:        include/services/services.h
+ * PURPOSE:     Private interface between SERVICES.EXE and ADVAPI32.DLL
+ * PROGRAMMER:  Eric Kohl
+ */
+
+#ifndef __SERVICES_SERVICES_H__
+#define __SERVICES_SERVICES_H__
+
+#define SCM_START_COMMAND 1
+
+typedef struct _SCM_START_PACKET
+{
+  ULONG Command;
+  ULONG Size;
+  WCHAR Arguments[1];
+} SCM_START_PACKET, *PSCM_START_PACKET;
+
+#endif /* __SERVICES_SERVICES_H__ */
+
+/* EOF */

Modified: trunk/reactos/lib/advapi32/service/sctrl.c
--- trunk/reactos/lib/advapi32/service/sctrl.c	2005-01-28 12:12:42 UTC (rev 13349)
+++ trunk/reactos/lib/advapi32/service/sctrl.c	2005-01-28 13:28:56 UTC (rev 13350)
@@ -13,6 +13,8 @@
 /* INCLUDES ******************************************************************/
 
 #include "advapi32.h"
+#include <services/services.h>
+
 #define NDEBUG
 #include <debug.h>
 
@@ -23,9 +25,15 @@
 {
   DWORD ThreadId;
   UNICODE_STRING ServiceName;
-  LPSERVICE_MAIN_FUNCTIONW MainFunction;
+  union
+  {
+    LPSERVICE_MAIN_FUNCTIONA lpFuncA;
+    LPSERVICE_MAIN_FUNCTIONW lpFuncW;
+  } Main;
   LPHANDLER_FUNCTION HandlerFunction;
   SERVICE_STATUS ServiceStatus;
+  BOOL bUnicode;
+  LPWSTR Arguments;
 } ACTIVE_SERVICE, *PACTIVE_SERVICE;
 
 
@@ -33,7 +41,6 @@
 
 static DWORD dwActiveServiceCount = 0;
 static PACTIVE_SERVICE lpActiveServices = NULL;
-/* static PHANDLE ActiveServicesThreadHandles; */ /* uncomment when in use */
 
 
 /* FUNCTIONS *****************************************************************/
@@ -80,16 +87,54 @@
 ScServiceMainStub(LPVOID Context)
 {
   PACTIVE_SERVICE lpService;
+  DWORD dwArgCount = 0;
+  DWORD dwLength = 0;
 
   lpService = (PACTIVE_SERVICE)Context;
 
   DPRINT("ScServiceMainStub() called\n");
 
-  /* FIXME: Send argc and argv (from command line) as arguments */
+  /* Count arguments */
+  while (lpService->Arguments[dwLength])
+    {
+      dwLength += wcslen(&lpService->Arguments[dwLength]) + 1;
+      dwArgCount++;
+    }
 
+  /* Build the argument vector and call the main service routine */
+  if (lpService->bUnicode)
+    {
+      LPWSTR *lpArgVector;
+      LPWSTR Ptr;
 
-  (lpService->MainFunction)(0, NULL);
+      lpArgVector = HeapAlloc(GetProcessHeap(),
+			      HEAP_ZERO_MEMORY,
+			      (dwArgCount + 1) * sizeof(LPWSTR));
+      if (lpArgVector == NULL)
+        return ERROR_OUTOFMEMORY;
 
+      dwArgCount = 0;
+      Ptr = lpService->Arguments;
+      while (*Ptr)
+	{
+	  lpArgVector[dwArgCount] = Ptr;
+
+	  dwArgCount++;
+	  Ptr += (wcslen(Ptr) + 1);
+	}
+      lpArgVector[dwArgCount] = NULL;
+
+      (lpService->Main.lpFuncW)(dwArgCount, lpArgVector);
+
+      HeapFree(GetProcessHeap(),
+	       0,
+	       lpArgVector);
+    }
+  else
+    {
+      (lpService->Main.lpFuncA)(0, NULL);
+    }
+
   return ERROR_SUCCESS;
 }
 
@@ -141,18 +186,30 @@
 }
 
 
-static BOOL
-ScServiceDispatcher(HANDLE hPipe,
-		    PUCHAR lpBuffer,
-		    DWORD dwBufferSize)
+
+static DWORD
+ScStartService(PSCM_START_PACKET StartPacket)
 {
   PACTIVE_SERVICE lpService;
   HANDLE ThreadHandle;
 
-  DPRINT("ScDispatcherLoop() called\n");
+  DPRINT("Size: %lu\n", StartPacket->Size);
+  DPRINT("Service: %S\n", &StartPacket->Arguments[0]);
 
-  lpService = &lpActiveServices[0];
+  lpService = ScLookupServiceByServiceName(&StartPacket->Arguments[0]);
+  if (lpService == NULL)
+    return ERROR_SERVICE_DOES_NOT_EXIST;
 
+  lpService->Arguments = HeapAlloc(GetProcessHeap(),
+				   HEAP_ZERO_MEMORY,
+				   StartPacket->Size);
+  if (lpService->Arguments == NULL)
+    return ERROR_OUTOFMEMORY;
+
+  memcpy(lpService->Arguments,
+	 StartPacket->Arguments,
+	 StartPacket->Size * sizeof(WCHAR));
+
   ThreadHandle = CreateThread(NULL,
 			      0,
 			      ScServiceMainStub,
@@ -160,22 +217,64 @@
 			      CREATE_SUSPENDED,
 			      &lpService->ThreadId);
   if (ThreadHandle == NULL)
-    return FALSE;
+    return ERROR_SERVICE_NO_THREAD;
 
   ResumeThread(ThreadHandle);
-
   CloseHandle(ThreadHandle);
 
-#if 0
+  return ERROR_SUCCESS;
+}
+
+
+static BOOL
+ScServiceDispatcher(HANDLE hPipe,
+		    PUCHAR lpBuffer,
+		    DWORD dwBufferSize)
+{
+  LPDWORD Buffer;
+  DWORD Count;
+  BOOL bResult;
+
+  DPRINT("ScDispatcherLoop() called\n");
+
+  Buffer = HeapAlloc(GetProcessHeap(),
+                     HEAP_ZERO_MEMORY,
+                     1024);
+  if (Buffer == NULL)
+    return FALSE;
+
   while (TRUE)
     {
       /* Read command from the control pipe */
+      bResult = ReadFile(hPipe,
+			 Buffer,
+			 1024,
+			 &Count,
+			 NULL);
+      if (bResult == FALSE)
+        {
+          DPRINT1("Pipe read failed\n");
+          return FALSE;
+        }
 
       /* Execute command */
+      switch (Buffer[0])
+        {
+          case SCM_START_COMMAND:
+            DPRINT("Start command\n");
+            ScStartService((PSCM_START_PACKET)Buffer);
+            break;
 
+          default:
+            DPRINT1("Unknown command %lu", Buffer[0]);
+            break;
+        }
     }
-#endif
 
+  HeapFree(GetProcessHeap(),
+           0,
+           Buffer);
+
   return TRUE;
 }
 
@@ -324,7 +423,8 @@
     {
       RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
 				       lpServiceStartTable[i].lpServiceName);
-      lpActiveServices[i].MainFunction = (LPSERVICE_MAIN_FUNCTIONW)lpServiceStartTable[i].lpServiceProc;
+      lpActiveServices[i].Main.lpFuncA = lpServiceStartTable[i].lpServiceProc;
+      lpActiveServices[i].bUnicode = FALSE;
     }
 
   dwError = ScConnectControlPipe(&hPipe);
@@ -400,7 +500,8 @@
     {
       RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
 			     lpServiceStartTable[i].lpServiceName);
-      lpActiveServices[i].MainFunction = lpServiceStartTable[i].lpServiceProc;
+      lpActiveServices[i].Main.lpFuncW = lpServiceStartTable[i].lpServiceProc;
+      lpActiveServices[i].bUnicode = TRUE;
     }
 
   dwError = ScConnectControlPipe(&hPipe);

Modified: trunk/reactos/subsys/system/services/database.c
--- trunk/reactos/subsys/system/services/database.c	2005-01-28 12:12:42 UTC (rev 13349)
+++ trunk/reactos/subsys/system/services/database.c	2005-01-28 13:28:56 UTC (rev 13350)
@@ -32,6 +32,7 @@
 #include <windows.h>
 #include <tchar.h>
 
+#include <services/services.h>
 #include "services.h"
 
 #define NDEBUG
@@ -521,9 +522,73 @@
 
 
 static NTSTATUS
-ScmStartService(PSERVICE Service,
-		PSERVICE_GROUP Group)
+ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments)
 {
+  PSCM_START_PACKET StartPacket;
+  DWORD TotalLength;
+#if 0
+  DWORD Length;
+#endif
+  PWSTR Ptr;
+  DWORD Count;
+
+  DPRINT("ScmSendStartCommand() called\n");
+
+  /* Calculate the total length of the start command line */
+  TotalLength = wcslen(Service->ServiceName.Buffer) + 1;
+#if 0
+  if (Arguments != NULL)
+  {
+    Ptr = Arguments;
+    while (*Ptr)
+    {
+      Length = wcslen(Ptr) + 1;
+      TotalLength += Length;
+      Ptr += Length;
+    }
+  }
+#endif
+  TotalLength++;
+
+  /* Allocate start command packet */
+  StartPacket = HeapAlloc(GetProcessHeap(),
+			  HEAP_ZERO_MEMORY,
+			  sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
+  if (StartPacket == NULL)
+    return STATUS_INSUFFICIENT_RESOURCES;
+
+  StartPacket->Command = SCM_START_COMMAND;
+  StartPacket->Size = TotalLength;
+  Ptr = &StartPacket->Arguments[0];
+  wcscpy(Ptr, Service->ServiceName.Buffer);
+  Ptr += (wcslen(Service->ServiceName.Buffer) + 1);
+
+  /* FIXME: Copy argument list */
+
+  *Ptr = 0;
+
+  /* Send the start command */
+  WriteFile(Service->ControlPipeHandle,
+	    StartPacket,
+	    sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
+	    &Count,
+	    NULL);
+
+  /* FIXME: Read the reply */
+
+  HeapFree(GetProcessHeap(),
+           0,
+           StartPacket);
+
+  DPRINT("ScmSendStartCommand() done\n");
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+ScmStartUserModeService(PSERVICE Service)
+{
   RTL_QUERY_REGISTRY_TABLE QueryTable[3];
   PROCESS_INFORMATION ProcessInformation;
   STARTUPINFOW StartupInfo;
@@ -532,153 +597,168 @@
   BOOL Result;
   NTSTATUS Status;
 
-  DPRINT("ScmStartService() called\n");
+  RtlInitUnicodeString(&ImagePath, NULL);
 
-  Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
-  DPRINT("Service->Type: %u\n", Service->Type);
+  /* Get service data */
+  RtlZeroMemory(&QueryTable,
+		sizeof(QueryTable));
 
-  if (Service->Type == SERVICE_KERNEL_DRIVER ||
-      Service->Type == SERVICE_FILE_SYSTEM_DRIVER ||
-      Service->Type == SERVICE_RECOGNIZER_DRIVER)
+  QueryTable[0].Name = L"Type";
+  QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+  QueryTable[0].EntryContext = &Type;
+
+  QueryTable[1].Name = L"ImagePath";
+  QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+  QueryTable[1].EntryContext = &ImagePath;
+
+  Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+				  Service->ServiceName.Buffer,
+				  QueryTable,
+				  NULL,
+				  NULL);
+  if (!NT_SUCCESS(Status))
     {
-      /* Load driver */
-      DPRINT("  Path: %wZ\n", &Service->RegistryPath);
-      Status = NtLoadDriver(&Service->RegistryPath);
+      DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
+      return Status;
     }
-  else
+  DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
+  DPRINT("Type: %lx\n", Type);
+
+  /* Create '\\.\pipe\net\NtControlPipe' instance */
+  Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
+						PIPE_ACCESS_DUPLEX,
+						PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+						100,
+						8000,
+						4,
+						30000,
+						NULL);
+  DPRINT("CreateNamedPipeW() done\n");
+  if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
     {
-      RtlInitUnicodeString(&ImagePath, NULL);
+      DPRINT1("Failed to create control pipe!\n");
+      return STATUS_UNSUCCESSFUL;
+    }
 
-      /* Get service data */
-      RtlZeroMemory(&QueryTable,
-		    sizeof(QueryTable));
+  StartupInfo.cb = sizeof(StartupInfo);
+  StartupInfo.lpReserved = NULL;
+  StartupInfo.lpDesktop = NULL;
+  StartupInfo.lpTitle = NULL;
+  StartupInfo.dwFlags = 0;
+  StartupInfo.cbReserved2 = 0;
+  StartupInfo.lpReserved2 = 0;
 
-      QueryTable[0].Name = L"Type";
-      QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
-      QueryTable[0].EntryContext = &Type;
+  Result = CreateProcessW(ImagePath.Buffer,
+			  NULL,
+			  NULL,
+			  NULL,
+			  FALSE,
+			  DETACHED_PROCESS | CREATE_SUSPENDED,
+			  NULL,
+			  NULL,
+			  &StartupInfo,
+			  &ProcessInformation);
+  RtlFreeUnicodeString(&ImagePath);
 
-      QueryTable[1].Name = L"ImagePath";
-      QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
-      QueryTable[1].EntryContext = &ImagePath;
+  if (!Result)
+    {
+      /* Close control pipe */
+      CloseHandle(Service->ControlPipeHandle);
+      Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
 
-      Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
-				      Service->ServiceName.Buffer,
-				      QueryTable,
-				      NULL,
-				      NULL);
-      if (NT_SUCCESS(Status))
-	{
-	  DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
-	  DPRINT("Type: %lx\n", Type);
+      DPRINT1("Starting '%S' failed!\n", Service->ServiceName.Buffer);
+      return STATUS_UNSUCCESSFUL;
+    }
 
-	  /* FIXME: create '\\.\pipe\net\NtControlPipe' instance */
-	  Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
-							PIPE_ACCESS_DUPLEX,
-							PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
-							100,
-							8000,
-							4,
-							30000,
-							NULL);
-	  DPRINT("CreateNamedPipeW() done\n");
-	  if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
-	    {
-	      DPRINT1("Failed to create control pipe!\n");
-	      Status = STATUS_UNSUCCESSFUL;
-	      goto Done;
-	    }
+  DPRINT("Process Id: %lu  Handle %lx\n",
+	 ProcessInformation.dwProcessId,
+	 ProcessInformation.hProcess);
+  DPRINT("Thread Id: %lu  Handle %lx\n",
+	 ProcessInformation.dwThreadId,
+	 ProcessInformation.hThread);
 
-	  StartupInfo.cb = sizeof(StartupInfo);
-	  StartupInfo.lpReserved = NULL;
-	  StartupInfo.lpDesktop = NULL;
-	  StartupInfo.lpTitle = NULL;
-	  StartupInfo.dwFlags = 0;
-	  StartupInfo.cbReserved2 = 0;
-	  StartupInfo.lpReserved2 = 0;
+  /* Get process and thread ids */
+  Service->ProcessId = ProcessInformation.dwProcessId;
+  Service->ThreadId = ProcessInformation.dwThreadId;
 
-	  Result = CreateProcessW(ImagePath.Buffer,
-				  NULL,
-				  NULL,
-				  NULL,
-				  FALSE,
-				  DETACHED_PROCESS | CREATE_SUSPENDED,
-				  NULL,
-				  NULL,
-				  &StartupInfo,
-				  &ProcessInformation);
-	  RtlFreeUnicodeString(&ImagePath);
+  /* Resume Thread */
+  ResumeThread(ProcessInformation.hThread);
 
-	  if (!Result)
-	    {
-	      /* Close control pipe */
-	      CloseHandle(Service->ControlPipeHandle);
-	      Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
+  /* Connect control pipe */
+  if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
+    {
+      DWORD dwProcessId = 0;
+      DWORD dwRead = 0;
 
-	      DPRINT1("Starting '%S' failed!\n", Service->ServiceName.Buffer);
-	      Status = STATUS_UNSUCCESSFUL;
-	    }
-	  else
-	    {
-	      DPRINT("Process Id: %lu  Handle %lx\n",
-		     ProcessInformation.dwProcessId,
-		     ProcessInformation.hProcess);
-	      DPRINT("Thread Id: %lu  Handle %lx\n",
-		     ProcessInformation.dwThreadId,
-		     ProcessInformation.hThread);
+      DPRINT("Control pipe connected!\n");
 
-	      /* Get process and thread ids */
-	      Service->ProcessId = ProcessInformation.dwProcessId;
-	      Service->ThreadId = ProcessInformation.dwThreadId;
+      /* Read thread id from pipe */
+      if (!ReadFile(Service->ControlPipeHandle,
+		    (LPVOID)&dwProcessId,
+		    sizeof(DWORD),
+		    &dwRead,
+		    NULL))
+	{
+	  DPRINT1("Reading the service control pipe failed (Error %lu)\n",
+		  GetLastError());
+	  Status = STATUS_UNSUCCESSFUL;
+	}
+      else
+	{
+	  DPRINT("Received process id %lu\n", dwProcessId);
 
-	      /* Resume Thread */
-	      ResumeThread(ProcessInformation.hThread);
+	  /* FIXME: Send start command */
 
-	      /* Connect control pipe */
-	      if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
-		{
-		  DWORD dwProcessId = 0;
-		  DWORD dwRead = 0;
+	  Status = STATUS_SUCCESS;
+	}
+    }
+  else
+    {
+      DPRINT("Connecting control pipe failed!\n");
 
-		  DPRINT("Control pipe connected!\n");
+      /* Close control pipe */
+      CloseHandle(Service->ControlPipeHandle);
+      Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
+      Service->ProcessId = 0;
+      Service->ThreadId = 0;
+      Status = STATUS_UNSUCCESSFUL;
+    }
 
-		  /* FIXME: Read thread id from pipe */
-		  if (!ReadFile(Service->ControlPipeHandle,
-				(LPVOID)&dwProcessId,
-				sizeof(DWORD),
-				&dwRead,
-				NULL))
-		    {
-		      DPRINT1("Reading the service control pipe failed (Error %lu)\n", GetLastError());
-		    }
-		  else
-		    {
-		      DPRINT("Received process id %lu\n", dwProcessId);
+  ScmSendStartCommand(Service, NULL);
 
-		      /* FIXME: Send start command */
+  /* Close process and thread handle */
+  CloseHandle(ProcessInformation.hThread);
+  CloseHandle(ProcessInformation.hProcess);
 
-		      Status = STATUS_SUCCESS;
-		    }
-		}
-	      else
-		{
-		  DPRINT("Connecting control pipe failed!\n");
+  return Status;
+}
 
-		  /* Close control pipe */
-		  CloseHandle(Service->ControlPipeHandle);
-		  Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
-		  Service->ProcessId = 0;
-		  Service->ThreadId = 0;
-		  Status = STATUS_UNSUCCESSFUL;
-		}
 
-	      /* Close process and thread handle */
-	      CloseHandle(ProcessInformation.hThread);
-	      CloseHandle(ProcessInformation.hProcess);
-	    }
-	}
+static NTSTATUS
+ScmStartService(PSERVICE Service,
+		PSERVICE_GROUP Group)
+{
+  NTSTATUS Status;
+
+  DPRINT("ScmStartService() called\n");
+
+  Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
+  DPRINT("Service->Type: %u\n", Service->Type);
+
+  if (Service->Type == SERVICE_KERNEL_DRIVER ||
+      Service->Type == SERVICE_FILE_SYSTEM_DRIVER ||
+      Service->Type == SERVICE_RECOGNIZER_DRIVER)
+    {
+      /* Load driver */
+      DPRINT("  Path: %wZ\n", &Service->RegistryPath);
+      Status = NtLoadDriver(&Service->RegistryPath);
     }
+  else
+    {
+      /* Start user-mode service */
+      Status = ScmStartUserModeService(Service);
+    }
 
-Done:
   DPRINT("ScmStartService() done (Status %lx)\n", Status);
 
   if (NT_SUCCESS(Status))