2 * Implementation of svchost.exe
4 * Copyright 2007 Google (Roy Shea)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Starting a service group:
24 * svchost /k service_group_name
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(svchost
);
37 static const WCHAR service_reg_path
[] = L
"System\\CurrentControlSet\\Services";
38 static const WCHAR svchost_path
[] = L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Svchost";
40 /* Allocate and initialize a WSTR containing the queried value */
41 static LPWSTR
GetRegValue(HKEY service_key
, const WCHAR
*value_name
)
51 ret
= RegQueryValueExW(service_key
, value_name
, NULL
, &type
, NULL
, ®_size
);
52 if (ret
!= ERROR_SUCCESS
)
57 /* Add space for potentially missing NULL terminators in initial alloc.
58 * The worst case REG_MULTI_SZ requires two NULL terminators. */
59 size
= reg_size
+ (2 * sizeof(WCHAR
));
60 value
= HeapAlloc(GetProcessHeap(), 0, size
);
62 ret
= RegQueryValueExW(service_key
, value_name
, NULL
, &type
,
63 (LPBYTE
)value
, ®_size
);
64 if (ret
!= ERROR_SUCCESS
)
66 HeapFree(GetProcessHeap(), 0, value
);
70 /* Explicitly NULL terminate the result */
71 value
[size
/ sizeof(WCHAR
) - 1] = '\0';
72 value
[size
/ sizeof(WCHAR
) - 2] = '\0';
77 /* Allocate and initialize a WSTR containing the expanded string */
78 static LPWSTR
ExpandEnv(LPWSTR string
)
81 LPWSTR expanded_string
;
86 size
= ExpandEnvironmentStringsW(string
, NULL
, size
);
89 WINE_ERR("cannot expand env vars in %s: %u\n",
90 wine_dbgstr_w(string
), GetLastError());
93 expanded_string
= HeapAlloc(GetProcessHeap(), 0,
94 (size
+ 1) * sizeof(WCHAR
));
95 if (ExpandEnvironmentStringsW(string
, expanded_string
, size
) == 0)
97 WINE_ERR("cannot expand env vars in %s: %u\n",
98 wine_dbgstr_w(string
), GetLastError());
99 HeapFree(GetProcessHeap(), 0, expanded_string
);
102 return expanded_string
;
105 /* Fill in service table entry for a specified service */
106 static BOOL
AddServiceElem(LPWSTR service_name
,
107 SERVICE_TABLE_ENTRYW
*service_table_entry
)
110 HKEY service_hkey
= NULL
;
111 LPWSTR service_param_key
= NULL
;
112 LPWSTR dll_name_short
= NULL
;
113 LPWSTR dll_name_long
= NULL
;
114 LPSTR dll_service_main
= NULL
;
115 HMODULE library
= NULL
;
116 LPSERVICE_MAIN_FUNCTIONW service_main_func
= NULL
;
117 BOOL success
= FALSE
;
121 WINE_TRACE("Adding element for %s\n", wine_dbgstr_w(service_name
));
123 /* Construct registry path to the service's parameters key */
124 size
= lstrlenW(service_reg_path
) + lstrlenW(L
"\\") + lstrlenW(service_name
) + lstrlenW(L
"\\") +
125 lstrlenW(L
"Parameters") + 1;
126 service_param_key
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
127 lstrcpyW(service_param_key
, service_reg_path
);
128 lstrcatW(service_param_key
, L
"\\");
129 lstrcatW(service_param_key
, service_name
);
130 lstrcatW(service_param_key
, L
"\\");
131 lstrcatW(service_param_key
, L
"Parameters");
132 service_param_key
[size
- 1] = '\0';
133 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, service_param_key
, 0,
134 KEY_READ
, &service_hkey
);
135 if (ret
!= ERROR_SUCCESS
)
137 WINE_ERR("cannot open key %s, err=%d\n",
138 wine_dbgstr_w(service_param_key
), ret
);
142 /* Find DLL associate with service from key */
143 dll_name_short
= GetRegValue(service_hkey
, L
"ServiceDll");
146 WINE_ERR("cannot find registry value ServiceDll for service %s\n",
147 wine_dbgstr_w(service_name
));
148 RegCloseKey(service_hkey
);
152 /* Expand environment variables in ServiceDll name*/
153 dll_name_long
= ExpandEnv(dll_name_short
);
156 WINE_ERR("failed to expand string %s\n",
157 wine_dbgstr_w(dll_name_short
));
158 RegCloseKey(service_hkey
);
162 /* Look for alternate to default ServiceMain entry point */
163 ret
= RegQueryValueExA(service_hkey
, "ServiceMain", NULL
, NULL
, NULL
, ®_size
);
164 if (ret
== ERROR_SUCCESS
)
166 /* Add space for potentially missing NULL terminator, allocate, and
167 * fill with the registry value */
169 dll_service_main
= HeapAlloc(GetProcessHeap(), 0, size
);
170 ret
= RegQueryValueExA(service_hkey
, "ServiceMain", NULL
, NULL
,
171 (LPBYTE
)dll_service_main
, ®_size
);
172 if (ret
!= ERROR_SUCCESS
)
174 RegCloseKey(service_hkey
);
177 dll_service_main
[size
- 1] = '\0';
179 RegCloseKey(service_hkey
);
181 /* Load the DLL and obtain a pointer to ServiceMain entry point */
182 library
= LoadLibraryExW(dll_name_long
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
);
185 WINE_ERR("failed to load library %s, err=%u\n",
186 wine_dbgstr_w(dll_name_long
), GetLastError());
189 if (dll_service_main
)
192 (LPSERVICE_MAIN_FUNCTIONW
) GetProcAddress(library
, dll_service_main
);
197 (LPSERVICE_MAIN_FUNCTIONW
) GetProcAddress(library
, "ServiceMain");
199 if (!service_main_func
)
201 WINE_ERR("cannot locate ServiceMain procedure in DLL for %s\n",
202 wine_dbgstr_w(service_name
));
203 FreeLibrary(library
);
207 if (GetProcAddress(library
, "SvchostPushServiceGlobals"))
209 WINE_FIXME("library %s expects undocumented SvchostPushServiceGlobals function to be called\n",
210 wine_dbgstr_w(dll_name_long
));
213 /* Fill in the service table entry */
214 service_table_entry
->lpServiceName
= service_name
;
215 service_table_entry
->lpServiceProc
= service_main_func
;
219 HeapFree(GetProcessHeap(), 0, service_param_key
);
220 HeapFree(GetProcessHeap(), 0, dll_name_short
);
221 HeapFree(GetProcessHeap(), 0, dll_name_long
);
222 HeapFree(GetProcessHeap(), 0, dll_service_main
);
226 /* Initialize the service table for a list (REG_MULTI_SZ) of services */
227 static BOOL
StartGroupServices(LPWSTR services
)
229 LPWSTR service_name
= NULL
;
230 SERVICE_TABLE_ENTRYW
*service_table
= NULL
;
234 /* Count the services to load */
236 service_name
= services
;
237 while (*service_name
!= '\0')
240 service_name
= service_name
+ lstrlenW(service_name
);
243 WINE_TRACE("Service group contains %d services\n", service_count
);
245 /* Populate the service table */
246 service_table
= HeapAlloc(GetProcessHeap(), 0,
247 (service_count
+ 1) * sizeof(SERVICE_TABLE_ENTRYW
));
249 service_name
= services
;
250 while (*service_name
!= '\0')
252 if (!AddServiceElem(service_name
, &service_table
[service_count
]))
254 HeapFree(GetProcessHeap(), 0, service_table
);
258 service_name
= service_name
+ lstrlenW(service_name
);
261 service_table
[service_count
].lpServiceName
= NULL
;
262 service_table
[service_count
].lpServiceProc
= NULL
;
264 /* Start the services */
265 if (!(ret
= StartServiceCtrlDispatcherW(service_table
)))
266 WINE_ERR("StartServiceCtrlDispatcherW failed to start %s: %u\n",
267 wine_dbgstr_w(services
), GetLastError());
269 HeapFree(GetProcessHeap(), 0, service_table
);
273 /* Find the list of services associated with a group name and start those
275 static BOOL
LoadGroup(PWCHAR group_name
)
277 HKEY group_hkey
= NULL
;
278 LPWSTR services
= NULL
;
281 WINE_TRACE("Loading service group for %s\n", wine_dbgstr_w(group_name
));
283 /* Lookup group_name value of svchost registry entry */
284 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, svchost_path
, 0,
285 KEY_READ
, &group_hkey
);
286 if (ret
!= ERROR_SUCCESS
)
288 WINE_ERR("cannot open key %s, err=%d\n",
289 wine_dbgstr_w(svchost_path
), ret
);
292 services
= GetRegValue(group_hkey
, group_name
);
293 RegCloseKey(group_hkey
);
296 WINE_ERR("cannot find registry value %s in %s\n",
297 wine_dbgstr_w(group_name
), wine_dbgstr_w(svchost_path
));
302 if (!(ret
= StartGroupServices(services
)))
303 WINE_TRACE("Failed to start service group\n");
305 HeapFree(GetProcessHeap(), 0, services
);
309 /* Load svchost group specified on the command line via the /k option */
310 int __cdecl
wmain(int argc
, WCHAR
*argv
[])
316 for (option_index
= 1; option_index
< argc
; option_index
++)
318 if (lstrcmpiW(argv
[option_index
], L
"/k") == 0 || lstrcmpiW(argv
[option_index
], L
"-k") == 0)
321 if (option_index
>= argc
)
323 WINE_ERR("Must specify group to initialize\n");
326 if (!LoadGroup(argv
[option_index
]))
328 WINE_ERR("Failed to load requested group: %s\n",
329 wine_dbgstr_w(argv
[option_index
]));
335 WINE_FIXME("Unrecognized option: %s\n",
336 wine_dbgstr_w(argv
[option_index
]));