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 hServiceDll
= LoadLibrary(DllPath
);
107 if (NULL
== hServiceDll
)
109 DPRINT1("Unable to load ServiceDll: %s\n", DllPath
);
113 ServiceMainFunc
= (LPSERVICE_MAIN_FUNCTION
)GetProcAddress(hServiceDll
, "ServiceMain");
115 /* Allocate a service node in the linked list */
116 Service
= HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE
));
119 DPRINT1("Not enough memory for service: %s\n", ServiceName
);
123 memset(Service
, 0, sizeof(SERVICE
));
124 Service
->Name
= HeapAlloc(GetProcessHeap(), 0, _tcslen(ServiceName
) + sizeof(TCHAR
));
125 if (NULL
== Service
->Name
)
127 DPRINT1("Not enough memory for service: %s\n", ServiceName
);
128 HeapFree(GetProcessHeap(), 0, Service
);
131 _tcscpy(Service
->Name
, ServiceName
);
133 Service
->hServiceDll
= hServiceDll
;
134 Service
->ServiceMainFunc
= ServiceMainFunc
;
136 Service
->Next
= FirstService
;
137 FirstService
= Service
;
146 PSERVICE Service
= FirstService
;
147 FirstService
= Service
->Next
;
149 FreeLibrary(Service
->hServiceDll
);
151 HeapFree(GetProcessHeap(), 0, Service
->Name
);
152 HeapFree(GetProcessHeap(), 0, Service
);
157 * Returns the number of services successfully loaded from the category
159 DWORD
LoadServiceCategory(LPCTSTR ServiceCategory
)
163 DWORD BufferSize
= REG_MAX_DATA_SIZE
;
164 TCHAR Buffer
[REG_MAX_DATA_SIZE
];
166 DWORD BufferIndex
= 0;
167 DWORD NrOfServices
= 0;
169 /* Get all the services in this category */
170 if (ERROR_SUCCESS
!= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, SVCHOST_REG_KEY
, 0, KEY_READ
, &hServicesKey
))
172 DPRINT1("Could not open service category: %s\n", ServiceCategory
);
176 if (ERROR_SUCCESS
!= RegQueryValueEx(hServicesKey
, ServiceCategory
, NULL
, &KeyType
, (LPBYTE
)Buffer
, &BufferSize
))
178 DPRINT1("Could not open service category (2): %s\n", ServiceCategory
);
179 RegCloseKey(hServicesKey
);
184 RegCloseKey(hServicesKey
);
186 /* Load services in the category */
187 ServiceName
= Buffer
;
188 while (_T('\0') != ServiceName
[0])
192 Length
= _tcslen(ServiceName
);
196 if (TRUE
== PrepareService(ServiceName
))
199 BufferIndex
+= (Length
+ 1) * sizeof(TCHAR
);
201 ServiceName
= &Buffer
[BufferIndex
];
207 int _tmain (int argc
, LPTSTR argv
[])
210 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 if (0 == NrOfServices
)
230 ServiceTable
= HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_TABLE_ENTRY
) * (NrOfServices
+ 1));
232 if (NULL
!= ServiceTable
)
234 PSERVICE Service
= FirstService
;
236 for (i
= 0; i
< NrOfServices
; ++i
)
238 ServiceTable
[i
].lpServiceName
= Service
->Name
;
239 ServiceTable
[i
].lpServiceProc
= Service
->ServiceMainFunc
;
240 Service
= Service
->Next
;
243 StartServiceCtrlDispatcher(ServiceTable
);
245 HeapFree(GetProcessHeap(), 0, ServiceTable
);
249 DPRINT1("Not enough memory for the service table, trying to allocate %u bytes\n", sizeof(SERVICE_TABLE_ENTRY
) * (NrOfServices
+ 1));