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 ******************************************************************/
19 /* DEFINES *******************************************************************/
21 static LPCTSTR SVCHOST_REG_KEY
= _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SvcHost");
22 static LPCTSTR SERVICE_KEY
= _T("SYSTEM\\CurrentControlSet\\Services\\");
23 static LPCTSTR PARAMETERS_KEY
= _T("\\Parameters");
25 #define SERVICE_KEY_LENGTH _tcslen(SERVICE_KEY);
26 #define REG_MAX_DATA_SIZE 2048
28 static PSERVICE FirstService
= NULL
;
30 /* FUNCTIONS *****************************************************************/
32 BOOL
PrepareService(LPCTSTR ServiceName
)
35 TCHAR ServiceKeyBuffer
[MAX_PATH
+ 1];
36 DWORD LeftOfBuffer
= sizeof(ServiceKeyBuffer
) / sizeof(ServiceKeyBuffer
[0]);
39 DWORD BufferSize
= MAX_PATH
+ 1;
41 HINSTANCE hServiceDll
;
42 TCHAR DllPath
[MAX_PATH
+ 2]; /* See MSDN on ExpandEnvironmentStrings() for ANSI strings for more details on + 2 */
43 LPSERVICE_MAIN_FUNCTION ServiceMainFunc
;
46 /* Compose the registry path to the service's "Parameter" key */
47 _tcsncpy(ServiceKeyBuffer
, SERVICE_KEY
, LeftOfBuffer
);
48 LeftOfBuffer
-= _tcslen(SERVICE_KEY
);
49 _tcsncat(ServiceKeyBuffer
, ServiceName
, LeftOfBuffer
);
50 LeftOfBuffer
-= _tcslen(ServiceName
);
51 _tcsncat(ServiceKeyBuffer
, PARAMETERS_KEY
, LeftOfBuffer
);
52 LeftOfBuffer
-= _tcslen(PARAMETERS_KEY
);
56 DPRINT1("Buffer overflow for service name: '%s'\n", ServiceName
);
60 /* Open the service registry key to find the dll name */
61 if (ERROR_SUCCESS
!= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, ServiceKeyBuffer
, 0, KEY_READ
, &hServiceKey
))
63 DPRINT1("Could not open service key (%s)\n", ServiceKeyBuffer
);
70 HeapFree(GetProcessHeap(), 0, Buffer
);
72 Buffer
= HeapAlloc(GetProcessHeap(), 0, BufferSize
);
75 DPRINT1("Not enough memory for service: %s\n", ServiceName
);
79 RetVal
= RegQueryValueEx(hServiceKey
, _T("ServiceDll"), NULL
, &KeyType
, (LPBYTE
)Buffer
, &BufferSize
);
81 } while (ERROR_MORE_DATA
== RetVal
);
84 RegCloseKey(hServiceKey
);
86 if (ERROR_SUCCESS
!= RetVal
|| 0 == BufferSize
)
88 DPRINT1("Could not read 'ServiceDll' value from service: %s, ErrorCode: 0x%x\n", ServiceName
, RetVal
);
89 HeapFree(GetProcessHeap(), 0, Buffer
);
93 /* Convert possible %SystemRoot% to a real path */
94 BufferSize
= ExpandEnvironmentStrings(Buffer
, DllPath
, sizeof(DllPath
));
97 DPRINT1("Invalid ServiceDll path: %s\n", Buffer
);
98 HeapFree(GetProcessHeap(), 0, Buffer
);
102 HeapFree(GetProcessHeap(), 0, Buffer
);
104 /* Load the service dll */
105 DPRINT1("Trying to load dll\n");
106 hServiceDll
= LoadLibrary(DllPath
);
108 if (NULL
== hServiceDll
)
110 DPRINT1("Unable to load ServiceDll: %s, ErrorCode: %u\n", DllPath
, GetLastError());
114 ServiceMainFunc
= (LPSERVICE_MAIN_FUNCTION
)GetProcAddress(hServiceDll
, "ServiceMain");
116 /* Allocate a service node in the linked list */
117 Service
= HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE
));
120 DPRINT1("Not enough memory for service: %s\n", ServiceName
);
124 memset(Service
, 0, sizeof(SERVICE
));
125 Service
->Name
= HeapAlloc(GetProcessHeap(), 0, _tcslen(ServiceName
) + sizeof(TCHAR
));
126 if (NULL
== Service
->Name
)
128 DPRINT1("Not enough memory for service: %s\n", ServiceName
);
129 HeapFree(GetProcessHeap(), 0, Service
);
132 _tcscpy(Service
->Name
, ServiceName
);
134 Service
->hServiceDll
= hServiceDll
;
135 Service
->ServiceMainFunc
= ServiceMainFunc
;
137 Service
->Next
= FirstService
;
138 FirstService
= Service
;
147 PSERVICE Service
= FirstService
;
148 FirstService
= Service
->Next
;
150 FreeLibrary(Service
->hServiceDll
);
152 HeapFree(GetProcessHeap(), 0, Service
->Name
);
153 HeapFree(GetProcessHeap(), 0, Service
);
158 * Returns the number of services successfully loaded from the category
160 DWORD
LoadServiceCategory(LPCTSTR ServiceCategory
)
164 DWORD BufferSize
= REG_MAX_DATA_SIZE
;
165 TCHAR Buffer
[REG_MAX_DATA_SIZE
];
167 DWORD BufferIndex
= 0;
168 DWORD NrOfServices
= 0;
170 /* Get all the services in this category */
171 if (ERROR_SUCCESS
!= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, SVCHOST_REG_KEY
, 0, KEY_READ
, &hServicesKey
))
173 DPRINT1("Could not open service category: %s\n", ServiceCategory
);
177 if (ERROR_SUCCESS
!= RegQueryValueEx(hServicesKey
, ServiceCategory
, NULL
, &KeyType
, (LPBYTE
)Buffer
, &BufferSize
))
179 DPRINT1("Could not open service category (2): %s\n", ServiceCategory
);
180 RegCloseKey(hServicesKey
);
185 RegCloseKey(hServicesKey
);
187 /* Load services in the category */
188 ServiceName
= Buffer
;
189 while (_T('\0') != ServiceName
[0])
193 Length
= _tcslen(ServiceName
);
197 if (TRUE
== PrepareService(ServiceName
))
200 BufferIndex
+= (Length
+ 1) * sizeof(TCHAR
);
202 ServiceName
= &Buffer
[BufferIndex
];
208 int _tmain (int argc
, LPTSTR argv
[])
211 LPSERVICE_TABLE_ENTRY ServiceTable
;
215 /* MS svchost.exe doesn't seem to print help, should we? */
219 if (_tcscmp(argv
[1], _T("-k")) != 0)
221 /* For now, we only handle "-k" */
225 NrOfServices
= LoadServiceCategory(argv
[2]);
227 DPRINT1("NrOfServices: %lu\n", NrOfServices
);
228 if (0 == NrOfServices
)
231 ServiceTable
= HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_TABLE_ENTRY
) * (NrOfServices
+ 1));
233 if (NULL
!= ServiceTable
)
236 PSERVICE Service
= FirstService
;
238 /* Fill the service table */
239 for (i
= 0; i
< NrOfServices
; ++i
)
241 DPRINT1("Loading service: %s\n", Service
->Name
);
242 ServiceTable
[i
].lpServiceName
= Service
->Name
;
243 ServiceTable
[i
].lpServiceProc
= Service
->ServiceMainFunc
;
244 Service
= Service
->Next
;
247 /* Set a NULL entry to end the service table */
248 ServiceTable
[i
].lpServiceName
= NULL
;
249 ServiceTable
[i
].lpServiceProc
= NULL
;
251 if (FALSE
== StartServiceCtrlDispatcher(ServiceTable
))
252 printf("Failed to start service control dispatcher, ErrorCode: %lu\n", GetLastError());
254 HeapFree(GetProcessHeap(), 0, ServiceTable
);
258 DPRINT1("Not enough memory for the service table, trying to allocate %u bytes\n", sizeof(SERVICE_TABLE_ENTRY
) * (NrOfServices
+ 1));
261 DPRINT1("Freeing services...\n");