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))
ekohl@svn.reactos.com wrote:
Use the service contol pipe to send a start command in order to start a service thread.
Hmm, I think this is not the right way to go. I've implemented basic SCM command pipe about year ago (it's in the "scmhack-12042004" CVS branch), but the right way is to use the RPC runtime and generated stub/proxy code. Robert Shearman wrote the IDL file for it some time ago and if we would allow temporary having MIDL generated code in SVN (since WIDL isn't mature enough to generate the stubs/proxys from this IDL) then we can just go the RPC way now...
- Filip