2 * PROJECT: ReactOS SvcHost
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: /base/services/svchost/svchost.c
5 * PURPOSE: Provide dll service loader
6 * PROGRAMMERS: Gregor Brunmar (gregor.brunmar@home.se)
9 /* INCLUDES ******************************************************************/
16 /* DEFINES *******************************************************************/
18 static LPCTSTR SVCHOST_REG_KEY
= _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SvcHost");
19 static LPCTSTR SERVICE_KEY
= _T("SYSTEM\\CurrentControlSet\\Services\\");
20 static LPCTSTR PARAMETERS_KEY
= _T("\\Parameters");
22 #define SERVICE_KEY_LENGTH _tcslen(SERVICE_KEY);
23 #define REG_MAX_DATA_SIZE 2048
25 static PSERVICE FirstService
= NULL
;
27 /* FUNCTIONS *****************************************************************/
29 BOOL
PrepareService(LPCTSTR ServiceName
)
32 TCHAR ServiceKeyBuffer
[MAX_PATH
+ 1];
33 DWORD LeftOfBuffer
= sizeof(ServiceKeyBuffer
) / sizeof(ServiceKeyBuffer
[0]);
36 DWORD BufferSize
= MAX_PATH
+ 1;
38 HINSTANCE hServiceDll
;
39 TCHAR DllPath
[MAX_PATH
+ 2]; /* See MSDN on ExpandEnvironmentStrings() for ANSI strings for more details on + 2 */
40 LPSERVICE_MAIN_FUNCTION ServiceMainFunc
;
43 /* Compose the registry path to the service's "Parameter" key */
44 _tcsncpy(ServiceKeyBuffer
, SERVICE_KEY
, LeftOfBuffer
);
45 LeftOfBuffer
-= _tcslen(SERVICE_KEY
);
46 _tcsncat(ServiceKeyBuffer
, ServiceName
, LeftOfBuffer
);
47 LeftOfBuffer
-= _tcslen(ServiceName
);
48 _tcsncat(ServiceKeyBuffer
, PARAMETERS_KEY
, LeftOfBuffer
);
49 LeftOfBuffer
-= _tcslen(PARAMETERS_KEY
);
53 DPRINT1("Buffer overflow for service name: '%s'\n", ServiceName
);
57 /* Open the service registry key to find the dll name */
58 if (ERROR_SUCCESS
!= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, ServiceKeyBuffer
, 0, KEY_READ
, &hServiceKey
))
60 DPRINT1("Could not open service key (%s)\n", ServiceKeyBuffer
);
67 HeapFree(GetProcessHeap(), 0, Buffer
);
69 Buffer
= HeapAlloc(GetProcessHeap(), 0, BufferSize
);
72 DPRINT1("Not enough memory for service: %s\n", ServiceName
);
76 RetVal
= RegQueryValueEx(hServiceKey
, _T("ServiceDll"), NULL
, &KeyType
, (LPBYTE
)Buffer
, &BufferSize
);
78 } while (ERROR_MORE_DATA
== RetVal
);
81 RegCloseKey(hServiceKey
);
83 if (ERROR_SUCCESS
!= RetVal
|| 0 == BufferSize
)
85 DPRINT1("Could not read 'ServiceDll' value from service: %s, ErrorCode: 0x%x\n", ServiceName
, RetVal
);
86 HeapFree(GetProcessHeap(), 0, Buffer
);
90 /* Convert possible %SystemRoot% to a real path */
91 BufferSize
= ExpandEnvironmentStrings(Buffer
, DllPath
, _countof(DllPath
));
94 DPRINT1("Invalid ServiceDll path: %s\n", Buffer
);
95 HeapFree(GetProcessHeap(), 0, Buffer
);
99 HeapFree(GetProcessHeap(), 0, Buffer
);
101 /* Load the service dll */
102 DPRINT("Trying to load dll\n");
103 hServiceDll
= LoadLibrary(DllPath
);
105 if (NULL
== hServiceDll
)
107 DPRINT1("Unable to load ServiceDll: %s, ErrorCode: %u\n", DllPath
, GetLastError());
111 ServiceMainFunc
= (LPSERVICE_MAIN_FUNCTION
)GetProcAddress(hServiceDll
, "ServiceMain");
113 /* Allocate a service node in the linked list */
114 Service
= HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE
));
117 DPRINT1("Not enough memory for service: %s\n", ServiceName
);
121 memset(Service
, 0, sizeof(SERVICE
));
122 Service
->Name
= HeapAlloc(GetProcessHeap(), 0, (_tcslen(ServiceName
)+1) * sizeof(TCHAR
));
123 if (NULL
== Service
->Name
)
125 DPRINT1("Not enough memory for service: %s\n", ServiceName
);
126 HeapFree(GetProcessHeap(), 0, Service
);
129 _tcscpy(Service
->Name
, ServiceName
);
131 Service
->hServiceDll
= hServiceDll
;
132 Service
->ServiceMainFunc
= ServiceMainFunc
;
134 Service
->Next
= FirstService
;
135 FirstService
= Service
;
140 VOID
FreeServices(VOID
)
144 PSERVICE Service
= FirstService
;
145 FirstService
= Service
->Next
;
147 FreeLibrary(Service
->hServiceDll
);
149 HeapFree(GetProcessHeap(), 0, Service
->Name
);
150 HeapFree(GetProcessHeap(), 0, Service
);
155 * Returns the number of services successfully loaded from the category
157 DWORD
LoadServiceCategory(LPCTSTR ServiceCategory
)
161 DWORD BufferSize
= REG_MAX_DATA_SIZE
;
162 TCHAR Buffer
[REG_MAX_DATA_SIZE
];
164 DWORD BufferIndex
= 0;
165 DWORD NrOfServices
= 0;
167 /* Get all the services in this category */
168 if (ERROR_SUCCESS
!= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, SVCHOST_REG_KEY
, 0, KEY_READ
, &hServicesKey
))
170 DPRINT1("Could not open service category: %s\n", ServiceCategory
);
174 if (ERROR_SUCCESS
!= RegQueryValueEx(hServicesKey
, ServiceCategory
, NULL
, &KeyType
, (LPBYTE
)Buffer
, &BufferSize
))
176 DPRINT1("Could not open service category (2): %s\n", ServiceCategory
);
177 RegCloseKey(hServicesKey
);
182 RegCloseKey(hServicesKey
);
184 /* Load services in the category */
185 ServiceName
= Buffer
;
186 while (_T('\0') != ServiceName
[0])
190 Length
= _tcslen(ServiceName
);
194 if (TRUE
== PrepareService(ServiceName
))
197 BufferIndex
+= Length
+ 1;
199 ServiceName
= &Buffer
[BufferIndex
];
205 int _tmain (int argc
, LPTSTR argv
[])
208 LPSERVICE_TABLE_ENTRY ServiceTable
;
212 /* MS svchost.exe doesn't seem to print help, should we? */
216 if (_tcscmp(argv
[1], _T("-k")) != 0)
218 /* For now, we only handle "-k" */
222 NrOfServices
= LoadServiceCategory(argv
[2]);
224 DPRINT("NrOfServices: %lu\n", NrOfServices
);
225 if (0 == NrOfServices
)
228 ServiceTable
= HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_TABLE_ENTRY
) * (NrOfServices
+ 1));
230 if (NULL
!= ServiceTable
)
233 PSERVICE Service
= FirstService
;
235 /* Fill the service table */
236 for (i
= 0; i
< NrOfServices
; i
++)
238 DPRINT("Loading service: %s\n", Service
->Name
);
239 ServiceTable
[i
].lpServiceName
= Service
->Name
;
240 ServiceTable
[i
].lpServiceProc
= Service
->ServiceMainFunc
;
241 Service
= Service
->Next
;
244 /* Set a NULL entry to end the service table */
245 ServiceTable
[i
].lpServiceName
= NULL
;
246 ServiceTable
[i
].lpServiceProc
= NULL
;
248 if (FALSE
== StartServiceCtrlDispatcher(ServiceTable
))
249 DPRINT1("Failed to start service control dispatcher, ErrorCode: %lu\n", GetLastError());
251 HeapFree(GetProcessHeap(), 0, ServiceTable
);
255 DPRINT1("Not enough memory for the service table, trying to allocate %u bytes\n", sizeof(SERVICE_TABLE_ENTRY
) * (NrOfServices
+ 1));
258 DPRINT("Freeing services...\n");