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 ******************************************************************/
21 /* DEFINES *******************************************************************/
23 static LPCTSTR SVCHOST_REG_KEY
= _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SvcHost");
24 static LPCTSTR SERVICE_KEY
= _T("SYSTEM\\CurrentControlSet\\Services\\");
25 static LPCTSTR PARAMETERS_KEY
= _T("\\Parameters");
27 #define SERVICE_KEY_LENGTH _tcslen(SERVICE_KEY);
28 #define REG_MAX_DATA_SIZE 2048
30 static PSERVICE FirstService
= NULL
;
32 /* FUNCTIONS *****************************************************************/
34 BOOL
PrepareService(LPCTSTR ServiceName
)
37 TCHAR ServiceKeyBuffer
[MAX_PATH
+ 1];
38 DWORD LeftOfBuffer
= sizeof(ServiceKeyBuffer
) / sizeof(ServiceKeyBuffer
[0]);
41 DWORD BufferSize
= MAX_PATH
+ 1;
43 HINSTANCE hServiceDll
;
44 TCHAR DllPath
[MAX_PATH
+ 2]; /* See MSDN on ExpandEnvironmentStrings() for ANSI strings for more details on + 2 */
45 LPSERVICE_MAIN_FUNCTION ServiceMainFunc
;
48 /* Compose the registry path to the service's "Parameter" key */
49 _tcsncpy(ServiceKeyBuffer
, SERVICE_KEY
, LeftOfBuffer
);
50 LeftOfBuffer
-= _tcslen(SERVICE_KEY
);
51 _tcsncat(ServiceKeyBuffer
, ServiceName
, LeftOfBuffer
);
52 LeftOfBuffer
-= _tcslen(ServiceName
);
53 _tcsncat(ServiceKeyBuffer
, PARAMETERS_KEY
, LeftOfBuffer
);
54 LeftOfBuffer
-= _tcslen(PARAMETERS_KEY
);
58 DPRINT1("Buffer overflow for service name: '%s'\n", ServiceName
);
62 /* Open the service registry key to find the dll name */
63 if (ERROR_SUCCESS
!= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, ServiceKeyBuffer
, 0, KEY_READ
, &hServiceKey
))
65 DPRINT1("Could not open service key (%s)\n", ServiceKeyBuffer
);
72 HeapFree(GetProcessHeap(), 0, Buffer
);
74 Buffer
= HeapAlloc(GetProcessHeap(), 0, BufferSize
);
77 DPRINT1("Not enough memory for service: %s\n", ServiceName
);
81 RetVal
= RegQueryValueEx(hServiceKey
, _T("ServiceDll"), NULL
, &KeyType
, (LPBYTE
)Buffer
, &BufferSize
);
83 } while (ERROR_MORE_DATA
== RetVal
);
86 RegCloseKey(hServiceKey
);
88 if (ERROR_SUCCESS
!= RetVal
|| 0 == BufferSize
)
90 DPRINT1("Could not read 'ServiceDll' value from service: %s, ErrorCode: 0x%x\n", ServiceName
, RetVal
);
91 HeapFree(GetProcessHeap(), 0, Buffer
);
95 /* Convert possible %SystemRoot% to a real path */
96 BufferSize
= ExpandEnvironmentStrings(Buffer
, DllPath
, sizeof(DllPath
));
99 DPRINT1("Invalid ServiceDll path: %s\n", Buffer
);
100 HeapFree(GetProcessHeap(), 0, Buffer
);
104 HeapFree(GetProcessHeap(), 0, Buffer
);
106 /* Load the service dll */
107 DPRINT1("Trying to load dll\n");
108 hServiceDll
= LoadLibrary(DllPath
);
110 if (NULL
== hServiceDll
)
112 DPRINT1("Unable to load ServiceDll: %s, ErrorCode: %u\n", DllPath
, GetLastError());
116 ServiceMainFunc
= (LPSERVICE_MAIN_FUNCTION
)GetProcAddress(hServiceDll
, "ServiceMain");
118 /* Allocate a service node in the linked list */
119 Service
= HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE
));
122 DPRINT1("Not enough memory for service: %s\n", ServiceName
);
126 memset(Service
, 0, sizeof(SERVICE
));
127 Service
->Name
= HeapAlloc(GetProcessHeap(), 0, _tcslen(ServiceName
) + sizeof(TCHAR
));
128 if (NULL
== Service
->Name
)
130 DPRINT1("Not enough memory for service: %s\n", ServiceName
);
131 HeapFree(GetProcessHeap(), 0, Service
);
134 _tcscpy(Service
->Name
, ServiceName
);
136 Service
->hServiceDll
= hServiceDll
;
137 Service
->ServiceMainFunc
= ServiceMainFunc
;
139 Service
->Next
= FirstService
;
140 FirstService
= Service
;
149 PSERVICE Service
= FirstService
;
150 FirstService
= Service
->Next
;
152 FreeLibrary(Service
->hServiceDll
);
154 HeapFree(GetProcessHeap(), 0, Service
->Name
);
155 HeapFree(GetProcessHeap(), 0, Service
);
160 * Returns the number of services successfully loaded from the category
162 DWORD
LoadServiceCategory(LPCTSTR ServiceCategory
)
166 DWORD BufferSize
= REG_MAX_DATA_SIZE
;
167 TCHAR Buffer
[REG_MAX_DATA_SIZE
];
169 DWORD BufferIndex
= 0;
170 DWORD NrOfServices
= 0;
172 /* Get all the services in this category */
173 if (ERROR_SUCCESS
!= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, SVCHOST_REG_KEY
, 0, KEY_READ
, &hServicesKey
))
175 DPRINT1("Could not open service category: %s\n", ServiceCategory
);
179 if (ERROR_SUCCESS
!= RegQueryValueEx(hServicesKey
, ServiceCategory
, NULL
, &KeyType
, (LPBYTE
)Buffer
, &BufferSize
))
181 DPRINT1("Could not open service category (2): %s\n", ServiceCategory
);
182 RegCloseKey(hServicesKey
);
187 RegCloseKey(hServicesKey
);
189 /* Load services in the category */
190 ServiceName
= Buffer
;
191 while (_T('\0') != ServiceName
[0])
195 Length
= _tcslen(ServiceName
);
199 if (TRUE
== PrepareService(ServiceName
))
202 BufferIndex
+= (Length
+ 1) * sizeof(TCHAR
);
204 ServiceName
= &Buffer
[BufferIndex
];
210 int _tmain (int argc
, LPTSTR argv
[])
213 LPSERVICE_TABLE_ENTRY ServiceTable
;
217 /* MS svchost.exe doesn't seem to print help, should we? */
221 if (_tcscmp(argv
[1], _T("-k")) != 0)
223 /* For now, we only handle "-k" */
227 NrOfServices
= LoadServiceCategory(argv
[2]);
229 DPRINT1("NrOfServices: %lu\n", NrOfServices
);
230 if (0 == NrOfServices
)
233 ServiceTable
= HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_TABLE_ENTRY
) * (NrOfServices
+ 1));
235 if (NULL
!= ServiceTable
)
238 PSERVICE Service
= FirstService
;
240 /* Fill the service table */
241 for (i
= 0; i
< NrOfServices
; ++i
)
243 DPRINT1("Loading service: %s\n", Service
->Name
);
244 ServiceTable
[i
].lpServiceName
= Service
->Name
;
245 ServiceTable
[i
].lpServiceProc
= Service
->ServiceMainFunc
;
246 Service
= Service
->Next
;
249 /* Set a NULL entry to end the service table */
250 ServiceTable
[i
].lpServiceName
= NULL
;
251 ServiceTable
[i
].lpServiceProc
= NULL
;
253 if (FALSE
== StartServiceCtrlDispatcher(ServiceTable
))
254 printf("Failed to start service control dispatcher, ErrorCode: %lu\n", GetLastError());
256 HeapFree(GetProcessHeap(), 0, ServiceTable
);
260 DPRINT1("Not enough memory for the service table, trying to allocate %u bytes\n", sizeof(SERVICE_TABLE_ENTRY
) * (NrOfServices
+ 1));
263 DPRINT1("Freeing services...\n");