ReactOS  0.4.13-dev-257-gfabbd7c
svchost.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Service Host
3  * LICENSE: BSD - See COPYING.ARM in the top level directory
4  * FILE: base/services/svchost/svchost.c
5  * PURPOSE: Main Service Host Implementation Routines
6  * PROGRAMMERS: ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include "svchost.h"
12 
13 #include <objidl.h>
14 
15 /* GLOBALS *******************************************************************/
16 
22 
23 /* FUNCTIONS *****************************************************************/
24 
26 LONG
27 WINAPI
29  _In_ struct _EXCEPTION_POINTERS * ExceptionInfo
30  )
31 {
32  /* Call the default OS handler */
33  return RtlUnhandledExceptionFilter(ExceptionInfo);
34 }
35 
36 VOID
37 WINAPI
39  _In_ DWORD dwControl
40  )
41 {
42  /* This is just a stub while we abort loading */
43  return;
44 }
45 
47 WINAPI
49  _In_ LPWSTR pszCmdLine
50  )
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 }
176 
177 DWORD
178 WINAPI
180  _In_ HKEY hKey,
181  _In_ PSVCHOST_OPTIONS pOptions
182  )
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,
193  REG_MULTI_SZ,
194  (PBYTE*)&ServiceNames);
195  if ((dwError == ERROR_SUCCESS) &&
196  ((ServiceNames == NULL) || (*ServiceNames == UNICODE_NULL)))
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 */
203  if (RegOpenKeyExW(hKey,
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",
216  &dwData) == ERROR_SUCCESS)
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 }
273 
274 VOID
275 WINAPI
277  _In_ PSVCHOST_OPTIONS lpOptions
278  )
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);
295  RegCloseKey(hKey);
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 }
336 
337 BOOL
338 WINAPI
341  )
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 */
369  RegCloseKey(hKey);
370  }
371 
372  /* Return if the value was set or not */
373  return DebugBreakOn;
374 }
375 
376 DWORD
377 WINAPI
379  _In_ LPCWSTR lpSubKey,
380  _Out_ PHKEY phKey
381  )
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 }
413 
414 VOID
415 WINAPI
417  _In_ PSVCHOST_SERVICE pService
418  )
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 */
439  if (RegQueryValueExW(hKey,
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 }
480 
481 VOID
482 WINAPI
485  _In_ BOOLEAN TimerOrWaitFired
486  )
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 }
515 
516 DWORD
517 WINAPI
519  _In_ PHANDLE phNewWaitObject,
521  _In_ HANDLE hObject,
522  _In_ PSVCHOST_STOP_CALLBACK pfnStopCallback,
523  _In_ PVOID pContext,
525  )
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",
564  ServiceName,
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",
577  ServiceName,
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",
596  ServiceName,
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",
605  ServiceName,
606  dwError);
607  }
608 
609 Quickie:
610  /* Drop the lock, and free the context if we failed */
612  if (dwError != ERROR_SUCCESS) MemFree(pSvcsStopCbContext);
613  return dwError;
614 }
615 
616 VOID
617 WINAPI
619  _In_ LPCWSTR lpServiceName,
620  _In_ DWORD dwExitCode
621  )
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 }
655 
656 PVOID
657 WINAPI
659  _In_ PSVCHOST_DLL pDll,
660  _In_ LPCSTR lpProcName,
661  _Out_ PDWORD lpdwError
662  )
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 }
718 
720 WINAPI
722  _In_ LPCWSTR pszManifestPath,
723  _In_ LPCWSTR pszDllPath,
724  _In_ PSVCHOST_SERVICE pService
725  )
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 }
757 
759 WINAPI
761  _In_ LPCWSTR pszManifestPath,
762  _In_ LPCWSTR pszDllPath,
763  _In_ PSVCHOST_SERVICE pService,
764  _Out_ PDWORD lpdwError
765  )
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 */
777  pDll = MemAlloc(HEAP_ZERO_MEMORY,
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 */
795  CopyMemory((PVOID)pDll->pszDllPath,
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 */
810  InsertTailList(&DllList, &pDll->DllList);
812 
813  /* And return it */
814  return pDll;
815 }
816 
817 VOID
818 WINAPI
820  _In_ PSVCHOST_SERVICE pService,
821  _Out_ PVOID *pServiceMain,
822  _Out_ PVOID *pPushServiceGlobals,
823  _Out_ PDWORD lpdwError
824  )
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*/
1015  RegQueryStringA(hKey,
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 */
1029 HaveDll:
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 
1041 Quickie:
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 }
1047 
1048 VOID
1049 WINAPI
1051  _In_ DWORD dwNumServicesArgs,
1052  _In_ LPWSTR *lpServiceArgVectors
1053  )
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 }
1163 
1165 WINAPI
1167  VOID
1168  )
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 }
1196 
1197 BOOLEAN
1198 WINAPI
1200  _In_ PSVCHOST_OPTIONS pOptions
1201  )
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 }
1244 
1245 VOID
1246 __cdecl
1248  VOID
1249  )
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 }
BOOL WINAPI ActivateActCtx(IN HANDLE hActCtx, OUT PULONG_PTR ulCookie)
Definition: actctx.c:237
LONG cServiceActiveThreadCount
Definition: svchost.h:151
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
PSVCHOST_GLOBALS g_pSvchostSharedGlobals
Definition: globals.c:50
VOID WINAPI DummySvchostCtrlHandler(_In_ DWORD dwControl)
Definition: svchost.c:38
LPSERVICE_MAIN_FUNCTIONW lpServiceProc
Definition: winsvc.h:184
UINT WINAPI SetErrorMode(IN UINT uMode)
Definition: except.c:753
void(WINAPI * LPSERVICE_MAIN_FUNCTIONW)(DWORD, LPWSTR *)
Definition: winsvc.h:177
#define TRUE
Definition: types.h:120
BOOL MemFree(IN PVOID lpMem)
Definition: utils.c:26
#define ERROR_SUCCESS
Definition: deptool.c:10
PSVCHOST_DLL WINAPI AddDll(_In_ LPCWSTR pszManifestPath, _In_ LPCWSTR pszDllPath, _In_ PSVCHOST_SERVICE pService, _Out_ PDWORD lpdwError)
Definition: svchost.c:760
DWORD dwCurrentState
Definition: winsvc.h:100
BOOLEAN WINAPI CallPerInstanceInitFunctions(_In_ PSVCHOST_OPTIONS pOptions)
Definition: svchost.c:1199
#define SEM_FAILCRITICALERRORS
Definition: rtltypes.h:69
#define __cdecl
Definition: accygwin.h:79
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define DBG_ERR(fmt,...)
Definition: svchost.h:35
PVOID WINAPI GetServiceDllFunction(_In_ PSVCHOST_DLL pDll, _In_ LPCSTR lpProcName, _Out_ PDWORD lpdwError)
Definition: svchost.c:658
#define KEY_READ
Definition: nt_native.h:1023
VOID WINAPI UnloadServiceDll(_In_ PSVCHOST_SERVICE pService)
Definition: svchost.c:416
PVOID MemAlloc(IN DWORD dwFlags, IN DWORD dwBytes)
Definition: utils.c:33
int WINAPI lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:170
PSVCHOST_SERVICE pService
Definition: svchost.h:162
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
Definition: loader.c:286
static SERVICE_STATUS ServiceStatus
Definition: dcomlaunch.c:27
DWORD WINAPI RegQueryDword(_In_ HKEY hKey, _In_ LPCWSTR pszValueName, _Out_ PDWORD pdwValue)
Definition: registry.c:78
static HANDLE ULONG_PTR dwData
Definition: file.c:35
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1517
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
DWORD dwServiceSpecificExitCode
Definition: winsvc.h:103
SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName, LPHANDLER_FUNCTION lpHandlerProc)
Definition: sctrl.c:732
HANDLE hActCtx
Definition: svchost.h:140
#define RPC_C_IMP_LEVEL_IDENTIFY
Definition: rpcdce.h:175
uint16_t * PWCHAR
Definition: typedefs.h:54
PSVCHOST_DLL WINAPI FindDll(_In_ LPCWSTR pszManifestPath, _In_ LPCWSTR pszDllPath, _In_ PSVCHOST_SERVICE pService)
Definition: svchost.c:721
#define LOAD_WITH_ALTERED_SEARCH_PATH
Definition: winbase.h:339
LIST_ENTRY DllList
Definition: svchost.c:17
LPWSTR lpServiceName
Definition: winsvc.h:183
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
#define InsertTailList(ListHead, Entry)
DWORD WINAPI RegQueryStringA(_In_ HKEY hKey, _In_ LPCWSTR pszValueName, _In_ DWORD dwExpectedType, _Out_ LPCSTR *ppszData)
Definition: registry.c:128
PSVCHOST_STOP_CALLBACK pfnStopCallback
Definition: svchost.h:153
LPCWSTR pszServiceName
Definition: svchost.h:149
#define NO_ERROR
Definition: dderror.h:5
#define lstrlenW
Definition: compat.h:407
BOOL WINAPI StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
Definition: sctrl.c:1123
#define pch(ap)
Definition: match.c:418
IMAGE_OPTIONAL_HEADER32 OptionalHeader
Definition: ntddk_ex.h:184
RPC_STATUS WINAPI RpcMgmtSetServerStackSize(ULONG ThreadStackSize)
Definition: rpc_server.c:1737
int WINAPI lstrcmpiW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:194
uint32_t ULONG_PTR
Definition: typedefs.h:63
BOOL WINAPI SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, LPSERVICE_STATUS lpServiceStatus)
Definition: sctrl.c:986
VOID WINAPI MemInit(_In_ HANDLE Heap)
Definition: globals.c:58
__callback LONG WINAPI SvchostUnhandledExceptionFilter(_In_ struct _EXCEPTION_POINTERS *ExceptionInfo)
Definition: svchost.c:28
BOOL WINAPI DeactivateActCtx(IN DWORD dwFlags, IN ULONG_PTR ulCookie)
Definition: actctx.c:268
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
DWORD dwCheckPoint
Definition: winsvc.h:104
#define SERVICE_STOPPED
Definition: winsvc.h:21
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
unsigned char * LPBYTE
Definition: typedefs.h:52
#define UNICODE_NULL
LIST_ENTRY DllList
Definition: svchost.h:136
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI DECLSPEC_HOTPATCH SetUnhandledExceptionFilter(IN LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
Definition: except.c:792
LPWSTR WINAPI GetCommandLineW(VOID)
Definition: proc.c:2043
#define REG_MULTI_SZ
Definition: nt_native.h:1501
VOID WINAPI ServiceStarter(_In_ DWORD dwNumServicesArgs, _In_ LPWSTR *lpServiceArgVectors)
Definition: svchost.c:1050
BOOL WINAPI InitializeSecurity(_In_ DWORD dwParam, _In_ DWORD dwAuthnLevel, _In_ DWORD dwImpLevel, _In_ DWORD dwCapabilities)
Definition: security.cxx:161
void WINAPI DebugBreak(void)
PWCHAR CmdLineBuffer
Definition: svchost.h:119
unsigned char BOOLEAN
CRITICAL_SECTION ListLock
Definition: svchost.c:18
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:697
smooth NULL
Definition: ftsmooth.c:416
#define _Out_
Definition: no_sal2.h:323
_In_ LPGUID _In_ PVOID Data
Definition: classpnp.h:778
VOID WINAPI BuildServiceArray(_In_ PSVCHOST_OPTIONS lpOptions)
Definition: svchost.c:276
const char * LPCSTR
Definition: xmlstorage.h:183
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
VOID __cdecl wmainCRTStartup(VOID)
Definition: svchost.c:1247
static SERVICE_STATUS_HANDLE(WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR
DWORD ServiceCount
Definition: svchost.c:19
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
DWORD WINAPI SvcRegisterStopCallback(_In_ PHANDLE phNewWaitObject, _In_ LPCWSTR ServiceName, _In_ HANDLE hObject, _In_ PSVCHOST_STOP_CALLBACK pfnStopCallback, _In_ PVOID pContext, _In_ ULONG dwFlags)
Definition: svchost.c:518
#define FreeLibrary(x)
Definition: compat.h:405
SERVICE_TABLE_ENTRYW *WINAPI BuildServiceTable(VOID)
Definition: svchost.c:1166
LPTSTR ServiceName
Definition: ServiceMain.c:15
#define GetProcessHeap()
Definition: compat.h:395
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4134
__wchar_t WCHAR
Definition: xmlstorage.h:180
struct _SVCHOST_SERVICE * pService
Definition: svchost.h:141
DWORD dwWaitHint
Definition: winsvc.h:105
VOID WINAPI ReleaseActCtx(IN HANDLE hActCtx)
Definition: actctx.c:208
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
#define CopyMemory
Definition: winbase.h:1633
DWORD dwWin32ExitCode
Definition: winsvc.h:102
unsigned long DWORD
Definition: ntddk_ex.h:95
DWORD dwServiceType
Definition: winsvc.h:99
PWCHAR CmdLine
Definition: svchost.h:120
VOID WINAPI SvchostStopCallback(_In_ PVOID Context, _In_ BOOLEAN TimerOrWaitFired)
Definition: svchost.c:483
VOID WINAPI SvchostBuildSharedGlobals(VOID)
Definition: globals.c:89
DWORD WINAPI RegQueryString(_In_ HKEY hKey, _In_ LPCWSTR pszValueName, _In_ DWORD dwExpectedType, _Out_ PBYTE *ppbData)
Definition: registry.c:107
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define DBG_TRACE(fmt,...)
Definition: svchost.h:36
VOID CALLBACK ServiceMain(DWORD argc, LPWSTR argv)
Definition: main.c:79
BOOL WINAPI FDebugBreakForService(_In_ LPCWSTR ServiceName)
Definition: svchost.c:339
LPCWSTR ServiceNames
Definition: svchost.c:20
VOID WINAPI AbortSvchostService(_In_ LPCWSTR lpServiceName, _In_ DWORD dwExitCode)
Definition: svchost.c:618
static const WCHAR L[]
Definition: oid.c:1250
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1175
DWORD WINAPI OpenServiceParametersKey(_In_ LPCWSTR lpSubKey, _Out_ PHKEY phKey)
Definition: svchost.c:378
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:414
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
LPCWSTR pszManifestPath
Definition: svchost.h:139
Definition: typedefs.h:117
PSVCHOST_SERVICE ServiceArray
Definition: svchost.c:21
DWORD WINAPI ReadPerInstanceRegistryParameters(_In_ HKEY hKey, _In_ PSVCHOST_OPTIONS pOptions)
Definition: svchost.c:179
#define ERROR_INVALID_DATA
Definition: winerror.h:116
#define _In_
Definition: no_sal2.h:204
DWORD dwControlsAccepted
Definition: winsvc.h:101
VOID WINAPI GetServiceMainFunctions(_In_ PSVCHOST_SERVICE pService, _Out_ PVOID *pServiceMain, _Out_ PVOID *pPushServiceGlobals, _Out_ PDWORD lpdwError)
Definition: svchost.c:819
LONG NTAPI RtlUnhandledExceptionFilter(IN struct _EXCEPTION_POINTERS *ExceptionInfo)
Definition: exception.c:306
#define __callback
Definition: sal.h:1746
#define NtCurrentPeb()
Definition: FLS.c:19
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define REG_EXPAND_SZ
Definition: nt_native.h:1494
#define SERVICE_WIN32
Definition: cmtypes.h:962
LPCWSTR pszDllPath
Definition: svchost.h:138
BOOL WINAPI RegisterWaitForSingleObject(OUT PHANDLE phNewWaitObject, IN HANDLE hObject, IN WAITORTIMERCALLBACK Callback, IN PVOID Context, IN ULONG dwMilliseconds, IN ULONG dwFlags)
Definition: synch.c:796
DWORD WINAPI ExpandEnvironmentStringsW(IN LPCWSTR lpSrc, IN LPWSTR lpDst, IN DWORD nSize)
Definition: environ.c:519
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
VOID WINAPI SvchostCharLowerW(_In_ LPCWSTR lpSrcStr)
Definition: globals.c:162
DWORD * PDWORD
Definition: pedump.c:68
VOID(WINAPI * PSVCHOST_INIT_GLOBALS)(_In_ PSVCHOST_GLOBALS Globals)
Definition: svchost.h:85
#define RtlImageNtHeader
Definition: compat.h:457
NTSYSAPI NTSTATUS __cdecl RtlSetProcessIsCritical(_In_ BOOLEAN NewValue, _Out_opt_ PBOOLEAN OldValue, _In_ BOOLEAN NeedBreaks)
#define RPC_C_AUTHN_LEVEL_PKT
Definition: rpcdce.h:149
struct tagContext Context
Definition: acpixf.h:1012
LPWSTR ServiceGroupName
Definition: svchost.h:122
HANDLE WINAPI CreateActCtxW(PCACTCTXW pActCtx)
Definition: actctx.c:104
unsigned int ULONG
Definition: retypes.h:1
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3381
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define GetProcAddress(x, y)
Definition: compat.h:410
#define SERVICE_QUERY_CONFIG
Definition: winsvc.h:53
#define ERROR_PATH_NOT_FOUND
Definition: winerror.h:106
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define INFINITE
Definition: serial.h:102
BOOL HasServiceGroup
Definition: svchost.h:121
VOID(CALLBACK * PSVCHOST_STOP_CALLBACK)(_In_ PVOID lpParameter, _In_ BOOLEAN TimerOrWaitFired)
Definition: svchost.h:43
#define REG_DWORD
Definition: sdbapi.c:596
BYTE * PBYTE
Definition: pedump.c:66
PSVCHOST_OPTIONS WINAPI BuildCommandOptions(_In_ LPWSTR pszCmdLine)
Definition: svchost.c:48
HMODULE hModule
Definition: animate.c:44
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define REG_SZ
Definition: layer.c:22