ReactOS 0.4.16-dev-297-gc569aee
svchost.c File Reference
#include "svchost.h"
#include <objidl.h>
Include dependency graph for svchost.c:

Go to the source code of this file.

Functions

__callback LONG WINAPI SvchostUnhandledExceptionFilter (_In_ struct _EXCEPTION_POINTERS *ExceptionInfo)
 
VOID WINAPI DummySvchostCtrlHandler (_In_ DWORD dwControl)
 
PSVCHOST_OPTIONS WINAPI BuildCommandOptions (_In_ LPWSTR pszCmdLine)
 
DWORD WINAPI ReadPerInstanceRegistryParameters (_In_ HKEY hKey, _In_ PSVCHOST_OPTIONS pOptions)
 
VOID WINAPI BuildServiceArray (_In_ PSVCHOST_OPTIONS lpOptions)
 
BOOL WINAPI FDebugBreakForService (_In_ LPCWSTR ServiceName)
 
DWORD WINAPI OpenServiceParametersKey (_In_ LPCWSTR lpSubKey, _Out_ PHKEY phKey)
 
VOID WINAPI UnloadServiceDll (_In_ PSVCHOST_SERVICE pService)
 
VOID WINAPI SvchostStopCallback (_In_ PVOID Context, _In_ BOOLEAN TimerOrWaitFired)
 
DWORD WINAPI SvcRegisterStopCallback (_Out_ PHANDLE phNewWaitObject, _In_ PCWSTR ServiceName, _In_ HANDLE hObject, _In_ PSVCHOST_STOP_CALLBACK pfnStopCallback, _In_ PVOID pContext, _In_ ULONG dwFlags)
 
VOID WINAPI AbortSvchostService (_In_ LPCWSTR lpServiceName, _In_ DWORD dwExitCode)
 
PVOID WINAPI GetServiceDllFunction (_In_ PSVCHOST_DLL pDll, _In_ LPCSTR lpProcName, _Out_ PDWORD lpdwError)
 
PSVCHOST_DLL WINAPI FindDll (_In_ LPCWSTR pszManifestPath, _In_ LPCWSTR pszDllPath, _In_ PSVCHOST_SERVICE pService)
 
PSVCHOST_DLL WINAPI AddDll (_In_ LPCWSTR pszManifestPath, _In_ LPCWSTR pszDllPath, _In_ PSVCHOST_SERVICE pService, _Out_ PDWORD lpdwError)
 
VOID WINAPI GetServiceMainFunctions (_In_ PSVCHOST_SERVICE pService, _Out_ PVOID *pServiceMain, _Out_ PVOID *pPushServiceGlobals, _Out_ PDWORD lpdwError)
 
VOID WINAPI ServiceStarter (_In_ DWORD dwNumServicesArgs, _In_ LPWSTR *lpServiceArgVectors)
 
SERVICE_TABLE_ENTRYW *WINAPI BuildServiceTable (VOID)
 
BOOLEAN WINAPI CallPerInstanceInitFunctions (_In_ PSVCHOST_OPTIONS pOptions)
 
VOID __cdecl wmainCRTStartup (VOID)
 

Variables

LIST_ENTRY DllList
 
CRITICAL_SECTION ListLock
 
DWORD ServiceCount
 
LPCWSTR ServiceNames
 
PSVCHOST_SERVICE ServiceArray
 

Function Documentation

◆ AbortSvchostService()

VOID WINAPI AbortSvchostService ( _In_ LPCWSTR  lpServiceName,
_In_ DWORD  dwExitCode 
)

Definition at line 618 of file svchost.c.

622{
623 SERVICE_STATUS_HANDLE scHandle;
625
626 /* Make us stopped and accept only query commands */
633 ServiceStatus.dwWin32ExitCode = dwExitCode;
634
635 /* Register a handler that will do nothing while we are being stopped */
636 scHandle = RegisterServiceCtrlHandlerW(lpServiceName,
638 if (scHandle)
639 {
640 /* Stop us */
641 if (!SetServiceStatus(scHandle, &ServiceStatus))
642 {
643 /* Tell the debugger if this didn't work */
644 DBG_ERR("AbortSvchostService: SetServiceStatus error %ld\n",
645 GetLastError());
646 }
647 }
648 else
649 {
650 /* Tell the debugger if we couldn't register the handler */
651 DBG_ERR("AbortSvchostService: RegisterServiceCtrlHandler failed %d\n",
652 GetLastError());
653 }
654}
static SERVICE_STATUS_HANDLE(WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR
static SERVICE_STATUS ServiceStatus
Definition: browser.c:22
SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName, LPHANDLER_FUNCTION lpHandlerProc)
Definition: sctrl.c:742
BOOL WINAPI SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, LPSERVICE_STATUS lpServiceStatus)
Definition: sctrl.c:997
DWORD dwServiceType
Definition: winsvc.h:99
DWORD dwWin32ExitCode
Definition: winsvc.h:102
DWORD dwControlsAccepted
Definition: winsvc.h:101
DWORD dwWaitHint
Definition: winsvc.h:105
DWORD dwCurrentState
Definition: winsvc.h:100
DWORD dwCheckPoint
Definition: winsvc.h:104
DWORD dwServiceSpecificExitCode
Definition: winsvc.h:103
VOID WINAPI DummySvchostCtrlHandler(_In_ DWORD dwControl)
Definition: svchost.c:38
#define DBG_ERR(fmt,...)
Definition: svchost.h:34
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define SERVICE_STOPPED
Definition: winsvc.h:21
#define SERVICE_QUERY_CONFIG
Definition: winsvc.h:53
#define SERVICE_WIN32
Definition: cmtypes.h:964

Referenced by ServiceStarter().

◆ AddDll()

PSVCHOST_DLL WINAPI AddDll ( _In_ LPCWSTR  pszManifestPath,
_In_ LPCWSTR  pszDllPath,
_In_ PSVCHOST_SERVICE  pService,
_Out_ PDWORD  lpdwError 
)

Definition at line 760 of file svchost.c.

766{
767 PSVCHOST_DLL pDll;
768 ULONG nDllPathLength, nManifestPathLength;
769 ASSERT(pszDllPath);
770 ASSERT(*pszDllPath);
771
772 /* Compute the length of the two paths */
773 nDllPathLength = lstrlenW(pszDllPath);
774 nManifestPathLength = lstrlenW(pszManifestPath);
775
776 /* Allocate the DLL entry for this service */
778 sizeof(*pDll) +
779 (nDllPathLength + nManifestPathLength) * sizeof(WCHAR) +
780 2 * sizeof(UNICODE_NULL));
781 if (pDll == NULL)
782 {
783 /* Bail out with failure */
784 *lpdwError = ERROR_NOT_ENOUGH_MEMORY;
785 return pDll;
786 }
787
788 /* Put the DLL path right after the DLL entry */
789 pDll->pszDllPath = (LPCWSTR)(pDll + 1);
790
791 /* Put the manifest path right past the DLL path (note the pointer math) */
792 pDll->pszManifestPath = pDll->pszDllPath + nDllPathLength + 1;
793
794 /* Now copy both paths */
796 pszDllPath,
797 sizeof(WCHAR) * nDllPathLength);
799 pszManifestPath,
800 sizeof(WCHAR) * nManifestPathLength);
801
802 /* Now set the service, and make sure both paths are NULL-terminated */
803 pDll->pService = pService;
804 ASSERT(pDll->hActCtx == NULL);
805 ASSERT(pDll->pszDllPath[nDllPathLength] == UNICODE_NULL);
806 ASSERT(pDll->pszManifestPath[nManifestPathLength] == UNICODE_NULL);
807
808 /* Finally, add the entry to the DLL database, while holding the lock */
812
813 /* And return it */
814 return pDll;
815}
PVOID MemAlloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: utils.c:33
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define NULL
Definition: types.h:112
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
#define lstrlenW
Definition: compat.h:750
#define InsertTailList(ListHead, Entry)
#define ASSERT(a)
Definition: mode.c:44
#define UNICODE_NULL
LIST_ENTRY DllList
Definition: svchost.h:93
struct _SVCHOST_SERVICE * pService
Definition: svchost.h:98
LPCWSTR pszDllPath
Definition: svchost.h:95
HANDLE hActCtx
Definition: svchost.h:97
LPCWSTR pszManifestPath
Definition: svchost.h:96
LIST_ENTRY DllList
Definition: svchost.c:17
CRITICAL_SECTION ListLock
Definition: svchost.c:18
uint32_t ULONG
Definition: typedefs.h:59
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
#define CopyMemory
Definition: winbase.h:1735
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
__wchar_t WCHAR
Definition: xmlstorage.h:180
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185

Referenced by GetServiceMainFunctions().

◆ BuildCommandOptions()

PSVCHOST_OPTIONS WINAPI BuildCommandOptions ( _In_ LPWSTR  pszCmdLine)

Definition at line 48 of file svchost.c.

51{
52 ULONG cbCmdLine;
53 PSVCHOST_OPTIONS pOptions;
54 LPWSTR pch, pGroupNameStart, lpServiceGroup;
55 LPWSTR *pGroupName = NULL;
56
57 /* Nothing to do without a command-line */
58 if (pszCmdLine == NULL) return ERROR_SUCCESS;
59
60 /* Get the length if the command line*/
61 cbCmdLine = sizeof(WCHAR) * lstrlenW(pszCmdLine) + sizeof(UNICODE_NULL);
62
63 /* Allocate a buffer for the parsed options */
64 pOptions = MemAlloc(HEAP_ZERO_MEMORY, cbCmdLine + sizeof(*pOptions));
65 if (pOptions == NULL) return ERROR_SUCCESS;
66
67 /* Copy the buffer into the parsed options block */
68 pOptions->CmdLineBuffer = (PWCHAR)(pOptions + 1);
69 memcpy(pOptions->CmdLineBuffer, pszCmdLine, cbCmdLine);
70
71 /* Set the command-line as being inside the block itself */
72 pch = pOptions->CmdLineBuffer;
73 ASSERT(pch);
74 pOptions->CmdLine = pch;
75
76 /* Now scan it */
77 while (*pch != UNICODE_NULL)
78 {
79 /* And look for the first space or TAB */
80 if ((*pch == ' ') || (*pch == '\t'))
81 {
82 /* Terminate the command-line there */
83 *pch++ = UNICODE_NULL;
84 break;
85 }
86
87 /* Keep searching */
88 pch++;
89 }
90
91 /* Lowercase the entire command line, but not the options */
92 SvchostCharLowerW(pOptions->CmdLine);
93
94 /* Loop over the command-line */
95 while (*pch != UNICODE_NULL)
96 {
97 /* Do an inner loop within it */
98 while (*pch != UNICODE_NULL)
99 {
100 /* And keep going until we find a space or TAB */
101 if ((*pch != ' ') && (*pch != '\t')) break;
102 pch++;
103 }
104
105 /* Did we reach the end? If so, bail out */
106 if (*pch == UNICODE_NULL) break;
107
108 /* We found the space -- is it followed by a dash or slash? */
109 if ((*pch == '-' || *pch == '/') && (*(pch + 1) != UNICODE_NULL))
110 {
111 /* Yep, and there's at least one character. Is it k or K? */
112 pch++;
113 if (*pch == 'k' || *pch == 'K')
114 {
115 /* Yep, we have a proper command line with a group! */
116 pOptions->HasServiceGroup = TRUE;
117 pGroupName = &pOptions->ServiceGroupName;
118 }
119
120 /* Keep going -- the name follows between spaces or quotes */
121 pch++;
122 }
123 else
124 {
125 /* Nope, so this might be the group being entered */
126 pGroupNameStart = pch;
127
128 /* Check if there's a quote */
129 if ((*pch == '"') && (*(pch + 1) != UNICODE_NULL))
130 {
131 /* There is, keep going until the quote is over with */
132 pGroupNameStart = ++pch;
133 while (*pch) if (*pch++ == '"') break;
134 }
135 else
136 {
137 /* No quote, so keep going until the next space or TAB */
138 while ((*pch) && ((*pch != ' ') && (*pch != '\t'))) pch++;
139 }
140
141 /* Now we have a space or quote delimited name, terminate it */
142 if (*pch) *pch++ = UNICODE_NULL;
143
144 /* Ok, so we have a string -- was it preceded by a -K or /K? */
145 if (pGroupName)
146 {
147 /* Yes it was, remember this, and don't overwrite it later */
148 *pGroupName = pGroupNameStart;
149 pGroupName = NULL;
150 }
151 }
152 }
153
154 /* Print out the service group for the debugger, and the command line */
155 DBG_TRACE("Command line : %ws\n", pszCmdLine);
156 lpServiceGroup = (pOptions->HasServiceGroup) ?
157 pOptions->ServiceGroupName : L"No";
158 DBG_TRACE("Service Group : %ws\n", lpServiceGroup);
159
160 /* Was a group specified? */
161 if (pOptions->HasServiceGroup == FALSE)
162 {
163 /* This isn't valid. Print out help on the debugger and fail */
164 DBG_TRACE("Generic Service Host\n\n"
165 "%ws [-k <key>] | [-r] | <service>\n\n"
166 " -k <key> Host all services whose ImagePath matches\n"
167 " %ws -k <key>.\n\n",
168 lpServiceGroup);
169 MemFree(pOptions);
170 pOptions = NULL;
171 }
172
173 /* Return the allocated option block, if valid*/
174 return pOptions;
175}
BOOL MemFree(IN PVOID lpMem)
Definition: utils.c:26
VOID WINAPI SvchostCharLowerW(_In_ LPCWSTR lpSrcStr)
Definition: globals.c:162
#define ERROR_SUCCESS
Definition: deptool.c:10
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define pch(ap)
Definition: match.c:418
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define L(x)
Definition: ntvdm.h:50
LPWSTR ServiceGroupName
Definition: svchost.h:79
BOOL HasServiceGroup
Definition: svchost.h:78
PWCHAR CmdLine
Definition: svchost.h:77
PWCHAR CmdLineBuffer
Definition: svchost.h:76
#define DBG_TRACE(fmt,...)
Definition: svchost.h:35
uint16_t * PWCHAR
Definition: typedefs.h:56
WCHAR * LPWSTR
Definition: xmlstorage.h:184

Referenced by wmainCRTStartup().

◆ BuildServiceArray()

VOID WINAPI BuildServiceArray ( _In_ PSVCHOST_OPTIONS  lpOptions)

Definition at line 276 of file svchost.c.

279{
280 DWORD dwError;
281 PSVCHOST_SERVICE pService;
282 LPCWSTR pszServiceName;
283 HKEY hKey;
284
285 /* Open the service host key */
287 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Svchost",
288 0,
289 KEY_READ,
290 &hKey);
291 if (dwError != ERROR_SUCCESS) return;
292
293 /* Read all the parameters for this service group */
294 dwError = ReadPerInstanceRegistryParameters(hKey, lpOptions);
296 if (dwError != ERROR_SUCCESS) return;
297
298 /* Acquire the database lock while we create the service group */
300
301 /* Loop the array of services for this group */
302 pszServiceName = ServiceNames;
303 while (*pszServiceName != UNICODE_NULL)
304 {
305 /* For each one, increment the amount of services we'llhost */
306 ServiceCount++;
307 pszServiceName += lstrlenW(pszServiceName) + 1;
308 }
309
310 /* We should host at least one... */
312
313 /* Now allocate an array to hold all their pointers */
314 ServiceArray = MemAlloc(HEAP_ZERO_MEMORY, sizeof(*pService) * ServiceCount);
315 if (ServiceArray)
316 {
317 /* Start at the beginning of the array */
318 pService = ServiceArray;
319
320 /* Loop through all the services */
321 pszServiceName = ServiceNames;
322 while (*pszServiceName != UNICODE_NULL)
323 {
324 /* Save the service's name and move to the next entry */
325 pService++->pszServiceName = pszServiceName;
326 pszServiceName += lstrlenW(pszServiceName) + 1;
327 }
328
329 /* We should have gotten the same count as earlier! */
330 ASSERT(pService == ServiceArray + ServiceCount);
331 }
332
333 /* We're done, drop the lock */
335}
#define RegCloseKey(hKey)
Definition: registry.h:49
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3333
unsigned long DWORD
Definition: ntddk_ex.h:95
FxAutoRegKey hKey
#define KEY_READ
Definition: nt_native.h:1023
LPCWSTR pszServiceName
Definition: svchost.h:106
PSVCHOST_SERVICE ServiceArray
Definition: svchost.c:21
LPCWSTR ServiceNames
Definition: svchost.c:20
DWORD WINAPI ReadPerInstanceRegistryParameters(_In_ HKEY hKey, _In_ PSVCHOST_OPTIONS pOptions)
Definition: svchost.c:179
DWORD ServiceCount
Definition: svchost.c:19
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12

Referenced by wmainCRTStartup().

◆ BuildServiceTable()

SERVICE_TABLE_ENTRYW *WINAPI BuildServiceTable ( VOID  )

Definition at line 1166 of file svchost.c.

1169{
1170 SERVICE_TABLE_ENTRYW *pServiceTable;
1171 ULONG i;
1172
1173 /* Acquire the database lock while we go over the services */
1175
1176 /* Allocate space for a NULL entry at the end as well, Windows needs this */
1177 pServiceTable = MemAlloc(HEAP_ZERO_MEMORY,
1178 (ServiceCount + 1) * sizeof(*pServiceTable));
1179 if (pServiceTable)
1180 {
1181 /* Go over all our registered services */
1182 for (i = 0; i < ServiceCount; i++)
1183 {
1184 /* And set their parameters in the service table */
1185 pServiceTable[i].lpServiceName = (LPWSTR)ServiceArray[i].pszServiceName;
1186 pServiceTable[i].lpServiceProc = ServiceStarter;
1187 DBG_TRACE("Added service table entry for %ws\n",
1188 pServiceTable[i].lpServiceName);
1189 }
1190 }
1191
1192 /* All done, can release the lock now */
1194 return pServiceTable;
1195}
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
LPWSTR lpServiceName
Definition: winsvc.h:183
LPSERVICE_MAIN_FUNCTIONW lpServiceProc
Definition: winsvc.h:184
VOID WINAPI ServiceStarter(_In_ DWORD dwNumServicesArgs, _In_ LPWSTR *lpServiceArgVectors)
Definition: svchost.c:1050

Referenced by wmainCRTStartup().

◆ CallPerInstanceInitFunctions()

BOOLEAN WINAPI CallPerInstanceInitFunctions ( _In_ PSVCHOST_OPTIONS  pOptions)

Definition at line 1199 of file svchost.c.

1202{
1203 PIMAGE_NT_HEADERS pNtHeaders;
1204 BOOLEAN bResult;
1205
1206 /* Is COM required for this host? */
1207 if (pOptions->CoInitializeSecurityParam != 0)
1208 {
1209 /* Yes, initialize COM security and parameters */
1210 bResult = InitializeSecurity(pOptions->CoInitializeSecurityParam,
1211 pOptions->AuthenticationLevel,
1212 pOptions->ImpersonationLevel,
1213 pOptions->AuthenticationCapabilities);
1214 if (bResult == FALSE) return FALSE;
1215 }
1216
1217 /* Do we have a custom RPC stack size? */
1218 if (pOptions->DefaultRpcStackSize != 0)
1219 {
1220 /* Yes, go set it */
1221 RpcMgmtSetServerStackSize(pOptions->DefaultRpcStackSize << 10);
1222 }
1223 else
1224 {
1225 /* Nope, get the NT headers from the image */
1226 pNtHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
1227 if (pNtHeaders)
1228 {
1229 /* And just use whatever the default thread stack is */
1231 }
1232 }
1233
1234 /* Is this host holding critical services? */
1235 if (pOptions->SystemCritical != FALSE)
1236 {
1237 /* Mark the process as critical if so */
1239 }
1240
1241 /* All done */
1242 return TRUE;
1243}
#define NtCurrentPeb()
Definition: FLS.c:22
unsigned char BOOLEAN
#define RtlImageNtHeader
Definition: compat.h:806
NTSYSAPI NTSTATUS __cdecl RtlSetProcessIsCritical(_In_ BOOLEAN NewValue, _Out_opt_ PBOOLEAN OldValue, _In_ BOOLEAN NeedBreaks)
RPC_STATUS WINAPI RpcMgmtSetServerStackSize(ULONG ThreadStackSize)
Definition: rpc_server.c:1734
BOOL WINAPI InitializeSecurity(_In_ DWORD dwParam, _In_ DWORD dwAuthnLevel, _In_ DWORD dwImpLevel, _In_ DWORD dwCapabilities)
Definition: security.cxx:161
IMAGE_OPTIONAL_HEADER32 OptionalHeader
Definition: ntddk_ex.h:184

Referenced by wmainCRTStartup().

◆ DummySvchostCtrlHandler()

VOID WINAPI DummySvchostCtrlHandler ( _In_ DWORD  dwControl)

Definition at line 38 of file svchost.c.

41{
42 /* This is just a stub while we abort loading */
43 return;
44}

Referenced by AbortSvchostService().

◆ FDebugBreakForService()

BOOL WINAPI FDebugBreakForService ( _In_ LPCWSTR  ServiceName)

Definition at line 339 of file svchost.c.

342{
343 DWORD Data;
344 BOOL DebugBreakOn = FALSE;
345 HKEY hKey, hSubKey;
346
347 /* Open the key for Svchost itself */
349 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Svchost",
350 0,
351 KEY_READ,
352 &hKey) == ERROR_SUCCESS)
353 {
354 /* That worked, now open the key for this service, if it exists */
355 if (RegOpenKeyExW(hKey, ServiceName, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
356 {
357 /* It does -- is there a DebugBreak value set? */
358 if (RegQueryDword(hSubKey, L"DebugBreak", &Data) == ERROR_SUCCESS)
359 {
360 /* There is! Check if it's 0 or 1 */
361 DebugBreakOn = Data != 0;
362 }
363
364 /* Done, close the service key */
365 RegCloseKey(hSubKey);
366 }
367
368 /* Done, close the svchost key */
370 }
371
372 /* Return if the value was set or not */
373 return DebugBreakOn;
374}
static WCHAR ServiceName[]
Definition: browser.c:19
DWORD WINAPI RegQueryDword(_In_ HKEY hKey, _In_ LPCWSTR pszValueName, _Out_ PDWORD pdwValue)
Definition: registry.c:78
unsigned int BOOL
Definition: ntddk_ex.h:94

Referenced by ServiceStarter().

◆ FindDll()

PSVCHOST_DLL WINAPI FindDll ( _In_ LPCWSTR  pszManifestPath,
_In_ LPCWSTR  pszDllPath,
_In_ PSVCHOST_SERVICE  pService 
)

Definition at line 721 of file svchost.c.

726{
727 PSVCHOST_DLL pDll, pFoundDll = NULL;
728 PLIST_ENTRY pNextEntry;
729 ASSERT(pszDllPath);
730
731 /* Lock the DLL database */
733
734 /* Scan through the database */
735 pNextEntry = DllList.Flink;
736 while (pNextEntry != &DllList)
737 {
738 /* Search for an existing DLL with the same parameters */
739 pDll = CONTAINING_RECORD(pNextEntry, SVCHOST_DLL, DllList);
740 if ((lstrcmpW(pDll->pszDllPath, pszDllPath) == 0) &&
741 (lstrcmpW(pDll->pszManifestPath, pszManifestPath) == 0) &&
742 (lstrcmpW(pDll->pService->pszServiceName, pService->pszServiceName) == 0))
743 {
744 /* Found it! */
745 pFoundDll = pDll;
746 break;
747 }
748
749 /* Keep searching */
750 pNextEntry = pNextEntry->Flink;
751 }
752
753 /* All done, release the lock and return what we found, if anything */
755 return pFoundDll;
756}
int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4243
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260

Referenced by GetServiceMainFunctions().

◆ GetServiceDllFunction()

PVOID WINAPI GetServiceDllFunction ( _In_ PSVCHOST_DLL  pDll,
_In_ LPCSTR  lpProcName,
_Out_ PDWORD  lpdwError 
)

Definition at line 658 of file svchost.c.

663{
665 PVOID lpAddress = NULL;
666 ULONG_PTR ulCookie = 0;
667
668 /* Activate the context */
669 if (ActivateActCtx(pDll->hActCtx, &ulCookie) == FALSE)
670 {
671 /* We couldn't, bail out */
672 if (lpdwError) *lpdwError = GetLastError();
673 DBG_ERR("ActivateActCtx for %ws failed. Error %d.\n",
674 pDll->pszDllPath,
675 GetLastError());
676 return lpAddress;
677 }
678
679 /* Check if we already have a loaded module for this service */
680 hModule = pDll->hModule;
681 if (!hModule)
682 {
683 /* We don't -- load it */
684 hModule = LoadLibraryExW(pDll->pszDllPath,
685 NULL,
687 if (!hModule)
688 {
689 /* We failed to load it, bail out */
690 if (lpdwError) *lpdwError = GetLastError();
691 DBG_ERR("LoadLibrary (%ws) failed. Error %d.\n",
692 pDll->pszDllPath,
693 GetLastError());
694 DeactivateActCtx(0, ulCookie);
695 return lpAddress;
696 }
697
698 /* Loaded! */
699 pDll->hModule = hModule;
700 }
701
702 /* Next, get the address being looked up*/
703 lpAddress = GetProcAddress(hModule, lpProcName);
704 if (!lpAddress && lpdwError)
705 {
706 /* We couldn't find it, write the error code and a debug statement */
707 *lpdwError = GetLastError();
708 DBG_ERR("GetProcAddress (%s) failed on DLL %ws. Error %d.\n",
709 lpProcName,
710 pDll->pszDllPath,
711 GetLastError());
712 }
713
714 /* All done, get rid of the activation context */
715 DeactivateActCtx(0, ulCookie);
716 return lpAddress;
717}
HMODULE hModule
Definition: animate.c:44
#define GetProcAddress(x, y)
Definition: compat.h:753
BOOL WINAPI DeactivateActCtx(IN DWORD dwFlags, IN ULONG_PTR ulCookie)
Definition: actctx.c:268
BOOL WINAPI ActivateActCtx(IN HANDLE hActCtx, OUT PULONG_PTR ulCookie)
Definition: actctx.c:237
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
Definition: loader.c:288
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define LOAD_WITH_ALTERED_SEARCH_PATH
Definition: winbase.h:370

Referenced by GetServiceMainFunctions().

◆ GetServiceMainFunctions()

VOID WINAPI GetServiceMainFunctions ( _In_ PSVCHOST_SERVICE  pService,
_Out_ PVOID pServiceMain,
_Out_ PVOID pPushServiceGlobals,
_Out_ PDWORD  lpdwError 
)

Definition at line 819 of file svchost.c.

825{
826 DWORD dwError, cbDllLength, cbData, dwType;
827 PSVCHOST_DLL pDll;
828 ACTCTXW actCtx;
829 LPCWSTR pszDllPath;
830 HKEY hKey;
831 HANDLE hActCtx;
832 LPWSTR lpData;
833 WCHAR szDllBuffer[MAX_PATH + 2], szManifestBuffer[MAX_PATH + 2];
834
835 /* Initialize the activation context we might need later */
836 RtlZeroMemory(&actCtx, sizeof(actCtx));
837 actCtx.cbSize = sizeof(actCtx);
838
839 /* We clean these up in our failure path so initialize them to NULL here */
840 hActCtx = NULL;
841 hKey = NULL;
842 lpData = NULL;
843 *lpdwError = ERROR_SUCCESS;
844
845 /* Null terminate the string buffers */
846 szDllBuffer[0] = UNICODE_NULL;
847 szManifestBuffer[0] = UNICODE_NULL;
848
849 /* Do we already have a DLL ready to go for this service? */
850 pDll = pService->pDll;
851 if (pDll != NULL) goto HaveDll;
852
853 /* Nope, we're starting from scratch. Open a handle to parameters key */
854 dwError = OpenServiceParametersKey(pService->pszServiceName, &hKey);
855 if (dwError)
856 {
857 *lpdwError = dwError;
858 ASSERT(*lpdwError != NO_ERROR);
859 goto Quickie;
860 }
861
862 /* Allocate enough space to hold a unicode path (NULL-terminated) */
863 cbData = MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL);
864 lpData = MemAlloc(0, cbData);
865 if (lpData == NULL)
866 {
867 /* No memory, bail out */
868 *lpdwError = ERROR_NOT_ENOUGH_MEMORY;
869 goto Quickie;
870 }
871
872 /* Query the DLL path */
873 lpData[0] = UNICODE_NULL;
874 dwError = RegQueryValueExW(hKey,
875 L"ServiceDll",
876 0,
877 &dwType,
878 (LPBYTE)lpData,
879 &cbData);
880 if (dwError != ERROR_SUCCESS)
881 {
882 *lpdwError = dwError;
883 DBG_ERR("RegQueryValueEx for the ServiceDll parameter of the %ws "
884 "service returned %u\n",
885 pService->pszServiceName,
886 dwError);
887 goto Quickie;
888 }
889
890 /* Is the registry data valid and present? */
891 if ((dwType != REG_EXPAND_SZ) || (lpData[0] == UNICODE_NULL))
892 {
893 /* Nope, bail out */
894 *lpdwError = ERROR_FILE_NOT_FOUND;
895 DBG_ERR("The ServiceDll parameter for the %ws service is not of type "
896 "REG_EXPAND_SZ\n",
897 pService->pszServiceName);
898 goto Quickie;
899 }
900
901 /* Convert the expandable path into an absolute path */
902 ExpandEnvironmentStringsW(lpData, szDllBuffer, MAX_PATH);
903 SvchostCharLowerW(szDllBuffer);
904
905 /* Check if the service has a manifest file associated with it */
906 cbData = MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL);
907 dwError = RegQueryValueExW(hKey,
908 L"ServiceManifest",
909 NULL,
910 &dwType,
911 (LPBYTE)lpData,
912 &cbData);
913 if (dwError != ERROR_SUCCESS)
914 {
915 /* Did we fail because one wasn't set? */
916 if ((dwError != ERROR_PATH_NOT_FOUND) &&
917 (dwError != ERROR_FILE_NOT_FOUND))
918 {
919 /* We failed for some other reason, bail out */
920 *lpdwError = dwError;
921 DBG_ERR("RegQueryValueEx for the ServiceManifest parameter of the "
922 "%ws service returned %u\n",
923 pService->pszServiceName,
924 dwError);
925 goto Quickie;
926 }
927
928 /* We have no manifest, make sure the buffer is empty */
929 szManifestBuffer[0] = UNICODE_NULL;
930
931 /* We're done with this buffer */
932 MemFree(lpData);
933 lpData = NULL;
934
935 /* Use the whole DLL path, since we don't have a manifest */
936 pszDllPath = szDllBuffer;
937 }
938 else
939 {
940 /* Do we have invalid registry data? */
941 if ((dwType != REG_EXPAND_SZ) || (*lpData == UNICODE_NULL))
942 {
943 /* Yes, pretend there's no manifest and bail out */
944 *lpdwError = ERROR_FILE_NOT_FOUND;
945 DBG_ERR("The ServiceManifest parameter for the %ws service is not "
946 "of type REG_EXPAND_SZ\n",
947 pService->pszServiceName);
948 goto Quickie;
949 }
950
951 /* Expand the string into our stack buffer */
952 ExpandEnvironmentStringsW(lpData, szManifestBuffer, MAX_PATH);
953
954 /* We no longer need the heap buffer*/
955 MemFree(lpData);
956 lpData = NULL;
957
958 /* Lowercase the manifest path */
959 SvchostCharLowerW(szManifestBuffer);
960
961 /* Now loop over the DLL path */
962 cbDllLength = lstrlenW(szDllBuffer);
963 while (cbDllLength)
964 {
965 /* From the end, until we find the first path separator */
966 if (szDllBuffer[cbDllLength] == '\\' || szDllBuffer[cbDllLength] == '/')
967 {
968 /* Use just a short name (cut out the rest of the path) */
969 pszDllPath = &szDllBuffer[cbDllLength + 1];
970 break;
971 }
972
973 /* Try the next character */
974 cbDllLength--;
975 }
976 }
977
978 /* See if we already have a matching DLL and manifest for this service */
979 pDll = FindDll(szManifestBuffer, pszDllPath, pService);
980 if (pDll == NULL)
981 {
982 /* We don't have it yet -- does this DLL have a manifest? */
983 if (szManifestBuffer[0] != UNICODE_NULL)
984 {
985 /* Create an activation context for it */
986 actCtx.lpSource = szManifestBuffer;
987 hActCtx = CreateActCtxW(&actCtx);
988 if (hActCtx == INVALID_HANDLE_VALUE)
989 {
990 /* We've failed to create one, bail out */
991 *lpdwError = GetLastError();
992 DBG_ERR("CreateActCtxW(%ws) for the %ws service returned %u\n",
993 szManifestBuffer,
994 pService->pszServiceName,
995 *lpdwError);
996 goto Quickie;
997 }
998 }
999
1000 /* Add this new DLL into the database */
1001 pDll = AddDll(szManifestBuffer, pszDllPath, pService, lpdwError);
1002 if (pDll)
1003 {
1004 /* Save the activation context and zero it so we don't release later */
1005 pDll->hActCtx = hActCtx;
1006 hActCtx = NULL;
1007 }
1008 }
1009
1010 /* We either found, added, or failed to add, the DLL for this service */
1011 ASSERT(!pService->pDll);
1012 pService->pDll = pDll;
1013
1014 /* In all cases, we will query the ServiceMain function, however*/
1016 L"ServiceMain",
1017 REG_SZ,
1018 &pService->pszServiceMain);
1019
1020 /* And now we'll check if we were able to create it earlier (or find it) */
1021 if (!pService->pDll)
1022 {
1023 /* We were not, so there's no point in going on */
1024 ASSERT(*lpdwError != NO_ERROR);
1025 goto Quickie;
1026 }
1027
1028 /* We do have a valid DLL, so now get the service main routine out of it */
1029HaveDll:
1030 *pServiceMain = GetServiceDllFunction(pDll,
1031 pService->pszServiceMain ?
1032 pService->pszServiceMain :
1033 "ServiceMain",
1034 lpdwError);
1035
1036 /* And now get the globals routine out of it (this one is optional) */
1037 *pPushServiceGlobals = GetServiceDllFunction(pDll,
1038 "SvchostPushServiceGlobals",
1039 NULL);
1040
1041Quickie:
1042 /* We're done, cleanup any resources we left behind */
1043 if (hKey != NULL) RegCloseKey(hKey);
1044 if (lpData != NULL) MemFree(lpData);
1045 if ((hActCtx) && (hActCtx != INVALID_HANDLE_VALUE)) ReleaseActCtx(hActCtx);
1046}
DWORD WINAPI RegQueryStringA(_In_ HKEY hKey, _In_ LPCWSTR pszValueName, _In_ DWORD dwExpectedType, _Out_ LPCSTR *ppszData)
Definition: registry.c:128
#define NO_ERROR
Definition: dderror.h:5
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4103
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define MAX_PATH
Definition: compat.h:34
VOID WINAPI ReleaseActCtx(IN HANDLE hActCtx)
Definition: actctx.c:208
DWORD WINAPI ExpandEnvironmentStringsW(IN LPCWSTR lpSrc, IN LPWSTR lpDst, IN DWORD nSize)
Definition: environ.c:519
HANDLE WINAPI CreateActCtxW(PCACTCTXW pActCtx)
Definition: actctx.c:102
#define REG_SZ
Definition: layer.c:22
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
#define REG_EXPAND_SZ
Definition: nt_native.h:1494
PVOID WINAPI GetServiceDllFunction(_In_ PSVCHOST_DLL pDll, _In_ LPCSTR lpProcName, _Out_ PDWORD lpdwError)
Definition: svchost.c:658
PSVCHOST_DLL WINAPI FindDll(_In_ LPCWSTR pszManifestPath, _In_ LPCWSTR pszDllPath, _In_ PSVCHOST_SERVICE pService)
Definition: svchost.c:721
DWORD WINAPI OpenServiceParametersKey(_In_ LPCWSTR lpSubKey, _Out_ PHKEY phKey)
Definition: svchost.c:378
PSVCHOST_DLL WINAPI AddDll(_In_ LPCWSTR pszManifestPath, _In_ LPCWSTR pszDllPath, _In_ PSVCHOST_SERVICE pService, _Out_ PDWORD lpdwError)
Definition: svchost.c:760
unsigned char * LPBYTE
Definition: typedefs.h:53
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define ERROR_PATH_NOT_FOUND
Definition: winerror.h:106

Referenced by ServiceStarter().

◆ OpenServiceParametersKey()

DWORD WINAPI OpenServiceParametersKey ( _In_ LPCWSTR  lpSubKey,
_Out_ PHKEY  phKey 
)

Definition at line 378 of file svchost.c.

382{
383 DWORD dwError;
384 HKEY hSubKey = NULL, hKey = NULL;
385 ASSERT(phKey);
386
387 /* Open the services key */
389 L"System\\CurrentControlSet\\Services",
390 0,
391 KEY_READ,
392 &hKey);
393 if (dwError == ERROR_SUCCESS)
394 {
395 /* Now open the service specific key, returning its handle */
396 dwError = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ, &hSubKey);
397 if (dwError == ERROR_SUCCESS)
398 {
399 /* And if that worked, return a handle to the parameters key */
400 dwError = RegOpenKeyExW(hSubKey,
401 L"Parameters",
402 0,
403 KEY_READ,
404 phKey);
405 }
406 }
407
408 /* Clean up any leftovers*/
409 if (hKey != NULL) RegCloseKey(hKey);
410 if (hSubKey != NULL) RegCloseKey(hSubKey);
411 return dwError;
412}

Referenced by GetServiceMainFunctions(), and UnloadServiceDll().

◆ ReadPerInstanceRegistryParameters()

DWORD WINAPI ReadPerInstanceRegistryParameters ( _In_ HKEY  hKey,
_In_ PSVCHOST_OPTIONS  pOptions 
)

Definition at line 179 of file svchost.c.

183{
184 DWORD dwError, dwData;
185 HKEY hSubKey;
186
187 /* We should have a name for this service group... */
188 ASSERT(pOptions->ServiceGroupName);
189
190 /* Query the group to see what services are part of it */
191 dwError = RegQueryString(hKey,
192 pOptions->ServiceGroupName,
195 if ((dwError == ERROR_SUCCESS) &&
197 {
198 /* If the key exists but there's no data, fail */
199 return ERROR_INVALID_DATA;
200 }
201
202 /* Open the key for this group */
204 pOptions->ServiceGroupName,
205 0,
206 KEY_READ,
207 &hSubKey) != ERROR_SUCCESS)
208 {
209 /* If we couldn't, bail out */
210 return dwError;
211 }
212
213 /* Check if we should initialize COM */
214 if (RegQueryDword(hSubKey,
215 L"CoInitializeSecurityParam",
217 {
218 /* Yes, remember the parameter to be sent when we do so */
219 pOptions->CoInitializeSecurityParam = dwData;
220 }
221
222 /* Also, if COM is requested, we must read a bunch more data... */
223 if (pOptions->CoInitializeSecurityParam)
224 {
225 /* First, read the authentication level, use a default if none is set */
226 if (RegQueryDword(hSubKey, L"AuthenticationLevel", &dwData))
227 {
228 pOptions->AuthenticationLevel = RPC_C_AUTHN_LEVEL_PKT;
229 }
230 else
231 {
232 pOptions->AuthenticationLevel = dwData;
233 }
234
235 /* Do the same for the impersonation level */
236 if (RegQueryDword(hSubKey, L"ImpersonationLevel", &dwData))
237 {
238 pOptions->ImpersonationLevel = RPC_C_IMP_LEVEL_IDENTIFY;
239 }
240 else
241 {
242 pOptions->ImpersonationLevel = dwData;
243 }
244
245 /* Do the same for the authentication capabilities */
246 if (RegQueryDword(hSubKey, L"AuthenticationCapabilities", &dwData))
247 {
248 pOptions->AuthenticationCapabilities = EOAC_NO_CUSTOM_MARSHAL |
249 EOAC_DISABLE_AAA;
250 }
251 else
252 {
253 pOptions->AuthenticationCapabilities = dwData;
254 }
255 }
256
257 /* Check if we need a specific RPC stack size, if not, we'll set it later */
258 if (!RegQueryDword(hSubKey, L"DefaultRpcStackSize", &dwData))
259 {
260 pOptions->DefaultRpcStackSize = dwData;
261 }
262
263 /* Finally, check if the services should be marked critical later on */
264 if (!RegQueryDword(hSubKey, L"SystemCritical", &dwData))
265 {
266 pOptions->SystemCritical = dwData;
267 }
268
269 /* All done reading the settings */
270 RegCloseKey(hSubKey);
271 return dwError;
272}
DWORD WINAPI RegQueryString(_In_ HKEY hKey, _In_ LPCWSTR pszValueName, _In_ DWORD dwExpectedType, _Out_ PBYTE *ppbData)
Definition: registry.c:107
static HANDLE ULONG_PTR dwData
Definition: file.c:35
#define REG_MULTI_SZ
Definition: nt_native.h:1501
BYTE * PBYTE
Definition: pedump.c:66
#define RPC_C_AUTHN_LEVEL_PKT
Definition: rpcdce.h:149
#define RPC_C_IMP_LEVEL_IDENTIFY
Definition: rpcdce.h:175
#define ERROR_INVALID_DATA
Definition: winerror.h:116

Referenced by BuildServiceArray().

◆ ServiceStarter()

VOID WINAPI ServiceStarter ( _In_ DWORD  dwNumServicesArgs,
_In_ LPWSTR lpServiceArgVectors 
)

Definition at line 1050 of file svchost.c.

1054{
1055 DWORD i, dwError = ERROR_FILE_NOT_FOUND;
1056 PSVCHOST_SERVICE ServiceEntry;
1057 LPCWSTR lpServiceName;
1059 PSVCHOST_INIT_GLOBALS ServiceInitGlobals = NULL;
1060
1061 /* Hold the lock while we start a service */
1063
1064 /* Get this service's name, and loop the database */
1065 lpServiceName = *lpServiceArgVectors;
1066 for (i = 0; i < ServiceCount; i++)
1067 {
1068 /* Try to find a match by name */
1069 if (!lstrcmpiW(lpServiceName, ServiceArray[i].pszServiceName)) break;
1070 }
1071
1072 /* Check if we didn't find it */
1073 if (i == ServiceCount)
1074 {
1075 /* This looks like a bogus attempt, bail out */
1077 return;
1078 }
1079
1080 /* We have it */
1081 ServiceEntry = &ServiceArray[i];
1082
1083 /* Should we breakpoint before loading this service? */
1084 if (FDebugBreakForService(lpServiceName) != FALSE)
1085 {
1086 /* Yep -- do it */
1087 DBG_TRACE("Attaching debugger before getting ServiceMain for %ws...\n",
1088 lpServiceName);
1089 DebugBreak();
1090 }
1091
1092 /* Get the callbacks for this service */
1094 (PVOID*)&ServiceMain,
1095 (PVOID*)&ServiceInitGlobals,
1096 &dwError);
1097
1098 /* If this service is valid and needs globals, but we don't have them... */
1099 if ((ServiceMain != NULL) &&
1100 (ServiceInitGlobals != NULL) &&
1102 {
1103 /* Go and build them for the first time! */
1105 }
1106
1107 /* We call a service if it has a main, or if wants globals and we have them */
1108 if (((ServiceInitGlobals != NULL) && (g_pSvchostSharedGlobals != NULL)) ||
1109 ((ServiceMain != NULL) && (ServiceInitGlobals == NULL)))
1110 {
1111 /* Therefore, make sure it won't be unloaded as we drop the lock */
1112 ServiceEntry->cServiceActiveThreadCount++;
1113 }
1114
1115 /* Drop the lock while we call into the service DLL */
1117
1118 /* First: does this service want globals? */
1119 if (ServiceInitGlobals != NULL)
1120 {
1121 /* Do we have any to give? */
1123 {
1124 /* Yes, push them to the service */
1125 ServiceInitGlobals(g_pSvchostSharedGlobals);
1126
1127 /* Does the service NOT have an entrypoint? */
1128 if (ServiceMain == NULL)
1129 {
1130 /* We're going to abort loading, it serves no use */
1131 if (lpServiceName != NULL)
1132 {
1133 AbortSvchostService(lpServiceName, dwError);
1134 }
1135
1136 /* And drop a reference count since it's not active anymore */
1137 UnloadServiceDll(ServiceEntry);
1138 }
1139 }
1140 else if (lpServiceName != NULL)
1141 {
1142 /* We have no globals to give, so don't even bother calling it */
1143 AbortSvchostService(lpServiceName, dwError);
1144 }
1145 }
1146
1147 /* Next up, does it have an entrypoint? */
1148 if (ServiceMain != NULL)
1149 {
1150 /* It does, so call it */
1151 DBG_TRACE("Calling ServiceMain for %ws...\n", lpServiceName);
1152 ServiceMain(dwNumServicesArgs, lpServiceArgVectors);
1153
1154 /* We're out of the service now, so we can drop a reference */
1155 UnloadServiceDll(ServiceEntry);
1156 }
1157 else if (lpServiceName != NULL)
1158 {
1159 /* It has no entrypoint, so abort its launch */
1160 AbortSvchostService(lpServiceName, dwError);
1161 }
1162}
VOID CALLBACK ServiceMain(DWORD argc, LPWSTR argv)
Definition: main.c:81
PSVCHOST_GLOBAL_DATA g_pSvchostSharedGlobals
Definition: globals.c:50
VOID WINAPI SvchostBuildSharedGlobals(VOID)
Definition: globals.c:89
int WINAPI lstrcmpiW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4262
LONG cServiceActiveThreadCount
Definition: svchost.h:108
VOID WINAPI GetServiceMainFunctions(_In_ PSVCHOST_SERVICE pService, _Out_ PVOID *pServiceMain, _Out_ PVOID *pPushServiceGlobals, _Out_ PDWORD lpdwError)
Definition: svchost.c:819
VOID WINAPI AbortSvchostService(_In_ LPCWSTR lpServiceName, _In_ DWORD dwExitCode)
Definition: svchost.c:618
BOOL WINAPI FDebugBreakForService(_In_ LPCWSTR ServiceName)
Definition: svchost.c:339
VOID WINAPI UnloadServiceDll(_In_ PSVCHOST_SERVICE pService)
Definition: svchost.c:416
VOID(WINAPI * PSVCHOST_INIT_GLOBALS)(_In_ PSVCHOST_GLOBAL_DATA Globals)
Definition: svchost.h:41
void WINAPI DebugBreak(void)
void(WINAPI * LPSERVICE_MAIN_FUNCTIONW)(DWORD, LPWSTR *)
Definition: winsvc.h:177

Referenced by BuildServiceTable().

◆ SvchostStopCallback()

VOID WINAPI SvchostStopCallback ( _In_ PVOID  Context,
_In_ BOOLEAN  TimerOrWaitFired 
)

Definition at line 483 of file svchost.c.

487{
488 PSVCHOST_CALLBACK_CONTEXT pSvcsStopCbContext = Context;
489 PSVCHOST_STOP_CALLBACK pfnStopCallback;
490
491 /* Hold the lock while we grab the callback */
493
494 /* Grab the callback, then clear it */
495 ASSERT(pSvcsStopCbContext->pService != NULL);
496 pfnStopCallback = pSvcsStopCbContext->pService->pfnStopCallback;
497 ASSERT(pfnStopCallback != NULL);
498 pSvcsStopCbContext->pService->pfnStopCallback = NULL;
499
500 /* Now release the lock, making sure the above was atomic */
502
503 /* Now make the callout */
504 DBG_TRACE("Call stop callback for service %ws, active threads %d\n",
505 pSvcsStopCbContext->pService->pszServiceName,
506 pSvcsStopCbContext->pService->cServiceActiveThreadCount);
507 pfnStopCallback(pSvcsStopCbContext->pContext, TimerOrWaitFired);
508
509 /* Decrement the active threads -- maybe the DLL can unload now */
510 UnloadServiceDll(pSvcsStopCbContext->pService);
511
512 /* We no longer need the context */
513 MemFree(pSvcsStopCbContext);
514}
WAITORTIMERCALLBACK PSVCHOST_STOP_CALLBACK
Definition: svc.h:75
PSVCHOST_SERVICE pService
Definition: svchost.h:119
PSVCHOST_STOP_CALLBACK pfnStopCallback
Definition: svchost.h:110

Referenced by SvcRegisterStopCallback().

◆ SvchostUnhandledExceptionFilter()

__callback LONG WINAPI SvchostUnhandledExceptionFilter ( _In_ struct _EXCEPTION_POINTERS ExceptionInfo)

Definition at line 28 of file svchost.c.

31{
32 /* Call the default OS handler */
33 return RtlUnhandledExceptionFilter(ExceptionInfo);
34}
LONG NTAPI RtlUnhandledExceptionFilter(IN struct _EXCEPTION_POINTERS *ExceptionInfo)
Definition: exception.c:313

Referenced by wmainCRTStartup().

◆ SvcRegisterStopCallback()

DWORD WINAPI SvcRegisterStopCallback ( _Out_ PHANDLE  phNewWaitObject,
_In_ PCWSTR  ServiceName,
_In_ HANDLE  hObject,
_In_ PSVCHOST_STOP_CALLBACK  pfnStopCallback,
_In_ PVOID  pContext,
_In_ ULONG  dwFlags 
)

Definition at line 518 of file svchost.c.

526{
527 ULONG i;
528 PSVCHOST_CALLBACK_CONTEXT pSvcsStopCbContext = NULL;
529 PSVCHOST_SERVICE pService = NULL;
530 DWORD dwError = ERROR_SUCCESS;
531
532 /* All parameters must be present */
533 if ((phNewWaitObject == NULL) ||
534 (ServiceName == NULL) ||
535 (hObject == NULL) ||
536 (pfnStopCallback == NULL))
537 {
538 /* Fail otherwise */
540 }
541
542 /* Don't allow new DLLs while we send notifications */
544
545 /* Scan all registered services */
546 for (i = 0; i < ServiceCount; i++)
547 {
548 /* Search for the service entry matching this service name */
549 if (lstrcmpiW(ServiceName, ServiceArray[i].pszServiceName) == 0)
550 {
551 /* Found it */
552 pService = &ServiceArray[i];
553 break;
554 }
555 }
556
557 /* Do we have a service? Does it already have a callback? */
558 if ((pService == NULL) || (pService->pfnStopCallback != NULL))
559 {
560 /* Affirmative, nothing for us to do */
561 dwError = ERROR_INVALID_DATA;
562 DBG_ERR("Service %ws missing or already registered for callback, "
563 "status %d\n",
565 dwError);
566 goto Quickie;
567 }
568
569 /* Allocate our internal context */
570 pSvcsStopCbContext = MemAlloc(HEAP_ZERO_MEMORY, sizeof(*pSvcsStopCbContext));
571 if (pSvcsStopCbContext == NULL)
572 {
573 /* We failed, bail out */
574 dwError = ERROR_NOT_ENOUGH_MEMORY;
575 DBG_ERR("MemAlloc for context block for service %ws failed, status "
576 "%d\n",
578 dwError);
579 goto Quickie;
580 }
581
582 /* Setup the context and register for the wait */
583 pSvcsStopCbContext->pContext = pContext;
584 pSvcsStopCbContext->pService = pService;
585 if (RegisterWaitForSingleObject(phNewWaitObject,
586 hObject,
588 pSvcsStopCbContext,
589 INFINITE,
590 dwFlags))
591 {
592 /* We now have an active thread associated with this wait */
593 pService->cServiceActiveThreadCount++;
594 pService->pfnStopCallback = pfnStopCallback;
595 DBG_TRACE("Registered stop callback for service %ws, active threads %d\n",
597 pService->cServiceActiveThreadCount);
598 }
599 else
600 {
601 /* Registration failed, bail out */
602 dwError = GetLastError();
603 DBG_ERR("Registration for stop callback for service %ws failed, "
604 "status %d\n",
606 dwError);
607 }
608
609Quickie:
610 /* Drop the lock, and free the context if we failed */
612 if (dwError != ERROR_SUCCESS) MemFree(pSvcsStopCbContext);
613 return dwError;
614}
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define INFINITE
Definition: serial.h:102
VOID WINAPI SvchostStopCallback(_In_ PVOID Context, _In_ BOOLEAN TimerOrWaitFired)
Definition: svchost.c:483
BOOL WINAPI RegisterWaitForSingleObject(OUT PHANDLE phNewWaitObject, IN HANDLE hObject, IN WAITORTIMERCALLBACK Callback, IN PVOID Context, IN ULONG dwMilliseconds, IN ULONG dwFlags)
Definition: synch.c:850
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1176

Referenced by SvchostBuildSharedGlobals().

◆ UnloadServiceDll()

VOID WINAPI UnloadServiceDll ( _In_ PSVCHOST_SERVICE  pService)

Definition at line 416 of file svchost.c.

419{
420 DWORD cbData;
421 DWORD Data;
422 DWORD dwType;
423 HKEY hKey = NULL;
424
425 cbData = 4;
426 Data = 0;
427
428 /* Grab the lock while we touch the thread count and potentially unload */
430
431 /* There is one less active callout into the DLL, it may be unloadabl now */
432 ASSERT(pService->cServiceActiveThreadCount > 0);
433 pService->cServiceActiveThreadCount--;
434
435 /* Try to open the service registry key */
436 if (OpenServiceParametersKey(pService->pszServiceName, &hKey) == ERROR_SUCCESS)
437 {
438 /* It worked -- check if we should unload the service when stopped */
440 L"ServiceDllUnloadOnStop",
441 0,
442 &dwType,
443 (LPBYTE)&Data,
444 &cbData) == ERROR_SUCCESS)
445 {
446 /* Make sure the data is correctly formatted */
447 if ((dwType == REG_DWORD) && (Data == 1))
448 {
449 /* Does the service still have active threads? */
450 if (pService->cServiceActiveThreadCount != 0)
451 {
452 /* Yep, so we can't kill it just yet */
453 DBG_TRACE("Skip Unload dll %ws for service %ws, "
454 "active threads %d\n",
455 pService->pDll->pszDllPath,
456 pService->pszServiceName,
457 pService->cServiceActiveThreadCount);
458 }
459 else
460 {
461 /* Nope, we're good to go */
462 DBG_TRACE("Unload dll %ws for service %ws\n",
463 pService->pDll->pszDllPath,
464 pService->pszServiceName);
465
466 /* Free the library and clear the module handle */
467 FreeLibrary(pService->pDll->hModule);
468 pService->pDll->hModule = NULL;
469 }
470 }
471 }
472 }
473
474 /* Drop the lock, unload is complete */
476
477 /* Close the parameters key if we had it */
478 if (hKey) RegCloseKey(hKey);
479}
#define FreeLibrary(x)
Definition: compat.h:748
#define REG_DWORD
Definition: sdbapi.c:596

Referenced by ServiceStarter(), and SvchostStopCallback().

◆ wmainCRTStartup()

VOID __cdecl wmainCRTStartup ( VOID  )

Definition at line 1247 of file svchost.c.

1250{
1251 PSVCHOST_OPTIONS lpOptions;
1252 SERVICE_TABLE_ENTRYW *pServiceTable;
1253 LPWSTR pszCmdLine;
1254
1255 /* Set a generic SEH filter and hard fail all critical errors */
1258
1259 /* Initialize the heap allocator */
1261
1262 /* Initialize the DLL database and lock */
1265
1266 /* Get the command-line and parse it to get the service group */
1267 pszCmdLine = GetCommandLineW();
1268 lpOptions = BuildCommandOptions(pszCmdLine);
1269 if (lpOptions == NULL)
1270 {
1271 /* Without a valid command-line, there's nothing for us to do */
1272 DBG_TRACE("Calling ExitProcess for %ws\n", pszCmdLine);
1273 ExitProcess(0);
1274 }
1275
1276 /* Now use the service group information to lookup all the services */
1277 BuildServiceArray(lpOptions);
1278
1279 /* Convert the list of services in this group to the SCM format */
1280 pServiceTable = BuildServiceTable();
1281 if (pServiceTable == NULL)
1282 {
1283 /* This is critical, bail out without it */
1284 MemFree(lpOptions);
1285 return;
1286 }
1287
1288 /* Initialize COM and RPC as needed for this service group */
1289 if (CallPerInstanceInitFunctions(lpOptions) == FALSE)
1290 {
1291 /* Exit with a special code indicating COM/RPC setup has failed */
1292 DBG_ERR("%s", "CallPerInstanceInitFunctions failed -- exiting!\n");
1293 ExitProcess(1);
1294 }
1295
1296 /* We're ready to go -- free the options buffer */
1297 MemFree(lpOptions);
1298
1299 /* And call into ADVAPI32 to get our services going */
1300 StartServiceCtrlDispatcherW(pServiceTable);
1301}
VOID WINAPI MemInit(_In_ HANDLE Heap)
Definition: globals.c:58
#define GetProcessHeap()
Definition: compat.h:736
UINT WINAPI SetErrorMode(IN UINT uMode)
Definition: except.c:751
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI DECLSPEC_HOTPATCH SetUnhandledExceptionFilter(IN LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
Definition: except.c:790
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1487
LPWSTR WINAPI GetCommandLineW(VOID)
Definition: proc.c:2019
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define SEM_FAILCRITICALERRORS
Definition: rtltypes.h:69
BOOL WINAPI StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
Definition: sctrl.c:1134
PSVCHOST_OPTIONS WINAPI BuildCommandOptions(_In_ LPWSTR pszCmdLine)
Definition: svchost.c:48
__callback LONG WINAPI SvchostUnhandledExceptionFilter(_In_ struct _EXCEPTION_POINTERS *ExceptionInfo)
Definition: svchost.c:28
VOID WINAPI BuildServiceArray(_In_ PSVCHOST_OPTIONS lpOptions)
Definition: svchost.c:276
SERVICE_TABLE_ENTRYW *WINAPI BuildServiceTable(VOID)
Definition: svchost.c:1166
BOOLEAN WINAPI CallPerInstanceInitFunctions(_In_ PSVCHOST_OPTIONS pOptions)
Definition: svchost.c:1199
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751

Variable Documentation

◆ DllList

LIST_ENTRY DllList

Definition at line 17 of file svchost.c.

Referenced by AddDll(), FindDll(), and wmainCRTStartup().

◆ ListLock

◆ ServiceArray

PSVCHOST_SERVICE ServiceArray

◆ ServiceCount

DWORD ServiceCount

◆ ServiceNames

LPCWSTR ServiceNames

Definition at line 20 of file svchost.c.

Referenced by BuildServiceArray(), and ReadPerInstanceRegistryParameters().