Writing a service that runs under svchost RRS feed

  • Question

  • Hi,

    I've been tryying to host my own Windows Service under svchost. All documentation that I have found so far redirects me to the article Q314056

    While this describes which registry keys are necessary to host the service dll under svchost, I am having trouble converting my windows service to a dll. When it is installed as a standalone service executable, say TestService1.exe, it runs fine.

    I've made a Dll with an empty DllMain, a ServiceHandler and a ServiceMain which registers the handler. This Dll however does not run when I try to host it under the svchost.

    The code for the Dll is as follows

    __declspec(dllexport) VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv);
    __declspec(dllexport) DWORD WINAPI HandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext);

    SERVICE_STATUS_HANDLE   hServiceStatusHandle;
    SERVICE_STATUS          ServiceStatus;

    const int nBufferSize = 500;
    CHAR pServiceName[nBufferSize+1];

                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
        return TRUE;

    VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)

        DWORD   status = 0;
        DWORD   specificError = 0xfffffff;
        ServiceStatus.dwServiceType        = SERVICE_WIN32_SHARE_PROCESS;
        ServiceStatus.dwCurrentState       = SERVICE_START_PENDING;
        ServiceStatus.dwWin32ExitCode      = 0;
        ServiceStatus.dwServiceSpecificExitCode = 0;
        ServiceStatus.dwCheckPoint         = 0;
        ServiceStatus.dwWaitHint           = 0;
        hServiceStatusHandle = RegisterServiceCtrlHandlerExA(pServiceName, HandlerEx, NULL);
        if (hServiceStatusHandle==0)
        ServiceStatus.dwCurrentState       = SERVICE_RUNNING;
        ServiceStatus.dwCheckPoint         = 0;
        ServiceStatus.dwWaitHint           = 0; 

        SetServiceStatus(hServiceStatusHandle, &ServiceStatus);

    DWORD WINAPI HandlerEx(
      DWORD dwControl,
      DWORD dwEventType,
      LPVOID lpEventData,
      LPVOID lpContext
            case SERVICE_CONTROL_STOP:
                ServiceStatus.dwWin32ExitCode = 0;
                ServiceStatus.dwCurrentState  = SERVICE_STOPPED;
                ServiceStatus.dwCheckPoint    = 0;
                ServiceStatus.dwWaitHint      = 0;
            case SERVICE_CONTROL_PAUSE:
                ServiceStatus.dwCurrentState = SERVICE_PAUSED;
                ServiceStatus.dwCurrentState = SERVICE_RUNNING;

            SetServiceStatus(hServiceStatusHandle,  &ServiceStatus);

        return NO_ERROR;

    Any suggestions and/or sample code would be welcome.Thanks!
    Tuesday, September 4, 2007 10:46 PM

All replies

  • Hi sandyshah,
    AFAIK, the interfaces that a service DLL would use to communicate with SVCHOST are not documented.  A reason that I seem to recall for this is that one could add their service to the list of services that any SVCHOST instance would run, and as 3rd party services have, at least in some circles, a reputation for not being as stable as Microsoft services, this could compromise all other services in the SVCHOST instance.  There are of course other factors at work here, as well.
    Why do you want to piggy-back onto SVCHOST?
    Tuesday, September 4, 2007 11:02 PM
  • Hi,

    My interest is academic. I am writing a research paper on Windows Services and one section deals with the different types of services and how they are started. So, far I've looked at regular and managed windows services and they are well documented. However, I've had no luck in services that are hosted in a common environment and run from a dll. I've read about 3rd party applications managing to do it, so it would definitely bear mentioning as it is an undocumented mechanism.


    Wednesday, September 5, 2007 10:32 PM
  • I've got a very basic service based on the code you provided, running in SVCHOST.EXE.
    The only modifications I made to the code were to add the following at the top of ServiceMain, so I could run DbgView and at least acknowledge that the DLL was loaded by SVCHOST.EXE:
    char szBuf[1024+1]={0};
    GetModuleFileName( NULL, szBuf, 1024 );
    OutputDebugString( " *** *** " );
    OutputDebugString( szBuf );
    OutputDebugString( " *** ***\n" );
    I also added a .DEF file to the project (I called the project ShTst):
    LIBRARY   ShTst
    The rest is all registry manipulation.
    I'm running the service in its own copy of SVCHOST.EXE; I've not tried tossing it into another service group but one could easily give it a shot.
    Here's the service registration:
    Windows Registry Editor Version 5.00
    "Description"="Test SVCHOST Service"
    Here's the SVCHOST group registration:
    Windows Registry Editor Version 5.00
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost]

    Note that I had to reboot to get the service to be recognized as a ... service, using this technique.
    Obviously, this example contains paths specific to my test system.  But adjusting appropriately, there should be no problem in getting SVCHOST to run the service, by modifying the registry as described and changing the project for the service DLL as described.
    In case it matters, my test environment is Windows XP SP2.
    The service DLL / SVCHOST interface can obviously be more complex than this (just look in the Parameters key of some SVCHOST hosted services in [HKLM\SYSTEM\CurrentControlSet\Services], for example - values like ServiceDllUnloadOnStop, ServiceMain, etc...).  But this presents a basic way to get a service hosted by SVCHOST.  Given what it is, I suppose the requirements for accomplishing this could change at any time, however...
    Wednesday, September 5, 2007 11:38 PM
  • Seems like there was a problem with my Exports.def Embarrassed

    It's working now and am hoping that no other issues crop up. Thanks a lot!
    Thursday, September 6, 2007 12:33 AM
  • Hi,

    I'm sorry I'm coming sooo late :) I'm using VB.Net to do the same thing. I'm a systems engineer in a developing country where we can't afford the cost for a windows domain - God forbid - and even the environment is too complex for that, because we run too many legacy applications. I too have a working EXE service that I want to run under SVCHOST, to hide it as much as possible from the eyes of notey users!!

    I have no trouble securing it later with SDDL, that I did. I need to run under SVCHOST.

    I'm having trouble creating the DLL service. I take the code from my already working EXE service, put it in place of an empty DLL class, I build it, register it to run under SVCHOST, but it takes like forever "starting".

    What's wrong here? Is it the use of system.timer? What is SVCHOST "waiting" for, if "he" is the one "waiting"?

    Any help please?
    Monday, June 8, 2009 5:53 PM
  • Hi khallaf,

    put it in place of an empty DLL class, I build it, register it to run under SVCHOST, but it takes like forever "starting".
    What do you mean, "register it to run under SVCHOST"?  Does the service ultimately start?  Or does the SCM time it out?

    In this case, it may be most helpful to simplify the environment - use the minimal code required to get a service running in SVCHOST, and see if you're able to recreate your problem.  If so, we'll start there.  If not, slowly add pieces of the puzzle until the problem can be reproduced...
    Monday, June 8, 2009 6:05 PM
  • How are you exporting ServiceMain? You cannot export C-style/native functions as you can with non-managed applications. You will need a wrapper DLL coded in C which hosts your .NET DLL.
    Monday, June 8, 2009 11:30 PM
  • ...And you had better hope that the process isn't already hosting a version of the .NET Framework that is different than the one your service would use...

    I too have a working EXE service that I want to run under SVCHOST, to hide it as much as possible from the eyes of notey users!!
    Why not just name your service executable SVCHOST.EXE? Or, why concern yourself with hiding the service at all?
    Tuesday, June 9, 2009 2:36 AM
  • Hi,

    OK, I'm not trying to hide it. I'm not an experienced coder, and I've never coded a class library before.

    Here is my code (Service is set as interactive in MMC, so that the messagebox would show)

    Public Class TService
        Public ticker As System.Timers.Timer
        Protected Overrides Sub OnStart(ByVal args() As String)
            ticker = New System.Timers.Timer(10000)
            AddHandler ticker.Elapsed, AddressOf monitor
        End Sub
        Public Sub monitor(ByVal pSender As Object, ByVal pArgs As System.Timers.ElapsedEventArgs)
            Exit Sub
        End Sub
        Protected Overrides Sub OnStop()
        End Sub
    End Class


    I tried two approaches, while I don't know if any is OK...

    1- I kept the EXE service as is, but changed the assembly type to Class Library in VStudio. I build it, and it does not complain.

    2- I created an empty Class Library project with the same name as "TService" and replaced whatever is there with the above code.  I build it, without "Overrides", and it builds with no trouble.

    Please don't go rough on me Big smile, I know my words sound funny and look like "evoking". I just need help.

    About "Registering" I mean that I modify the registry entries of the original EXE service, plus add service group in order to make it run under SVCHOST. This part I have no trouble with.

    Any comment?

    Tuesday, June 9, 2009 3:56 AM
  • As wj32 inquired - how are you handling the export of the function for SVCHOST to call?
    Tuesday, June 9, 2009 4:02 AM
  • Hi again,

    I'm sorry if I looked like nag, but I gave up on the .net. I could only understand that the entry point MUST be named ServiceMain, otherwise svchost.exe will not distinguish it. I could not do it in .net.

    While I have already started teaching myself C++ Smile, I went back to SandyShah's code, tried to compile it in an empty Win32 DLL, using VC++ 6.0, but it always complains about the function RegisterServiceCtrlHandlerExA.

    I already know this function is exported in advapi32.dll, but I don't really know how to define it in the source file.

    Could you press on your nerves Big smile and tell me just how to compile a DLL like the one in this post, and I could take my knowledge forward with it slowly step by step, as I learn further?

    If you just do it, I promise I won't be asking again Big smile

    Best Regards,

    Sunday, July 12, 2009 5:50 AM
  • Hi Khallaf,

    Don't sweat asking for help!

    But first, let me inquire as to why you're using such an old version of VC++, especially when the express editions of later versions are free.

    Probably, to get it to work in VC++ 6.0, you need to define _WIN32_WINNT to e.g. 0x0501 in the project settings, in stdafx.h if you're using PCH, or at the top of the source file...
    #define _WIN32_WINNT 0x0501 
    Sunday, July 12, 2009 7:16 AM
  • Hi,

    Thanks for your reply. The reason I used VC++ 6.0 is that: The express version only has DLL project in CLR (which I don't think would work and yet I have tried it!!), and in the professional version the code in the post produces so many errors on compile on IDE. I know I may be missing a lot. C++ is not my ground at all, nor is deep system programming. I'm a systems engineer and I use programming for automation, and I do it mainly in .net and shell scripts.

    It might not be possible, but could you describe in steps how to compile SandyShah's code? It would take me more time after to really get my own project to work, but at least I'll have some ground to stand on. It is only that I need to see it move.


    Sunday, July 12, 2009 8:23 AM
  • I no longer have VC++ 6.0 installed.  But in VC++ 2008 Express...
    + File->New Project, Win32 Project, give it a name, OK.
    + Application Settings tab, DLL radio button, OK
    + dllmain.cpp, select all, paste code, add #include "stdafx.h" at top

    Code will compile with 0 errors, 1 warning about strcpy deprecation.  For expository purposes, this message can be ignored.

    Monday, July 13, 2009 3:24 AM
  • At last, compiles, but still the same as with .net. Error 127 "The sepcified procedure could not be found". I followed steps carefully, matched everything, even the exports file. My test env. is XP SP3.
    Monday, July 13, 2009 11:50 AM
  • The steps described suggest how one may compile the given code.

    To export the function, change the Linker settings in the project properties so the Input tab->Module Definition File references the .def file you created.
    Monday, July 13, 2009 12:41 PM
  • Thanks molotov, ur da man. Wink
    Tuesday, July 14, 2009 12:29 AM
  • So, I take it you got it working?
    Tuesday, July 14, 2009 2:20 AM
  • Indeed, it did. Thanks. Yes, it runs under its own svchost instance, though being started within the netsvcs group, but that is the least to care about. It would be better of course, specially with protective SDDL configuration, Safe-Mode startup, but I'll keep that to the end.
    Tuesday, July 14, 2009 2:41 PM
  • Curious - are you working on some come commercial or other product?

    The registry settings to configure the service to be in its own SVCHOST group are provided elsewhere in this topic.
    Wednesday, July 15, 2009 2:29 AM
  • More or less, but no. It is funny and sad in the same time. Shops that cannot afford M$ AD license requirements will mostly suffer this same problem...

    Legacy apps added to the absence of centralized control make automation more of a nightmare to any admin. If you add this to a third-world management, where there no care about control and policy violation punishment - yes believe it - as long as profits are running, you get the picture that fitsmy situation.

    I could have not needed any of this, and I could have been working happily. But, I want you to regard this - modified - conversation between a sysadmin and a user:

    - the user complains about some sharing problem.
    - the sysadmin tries to help the user with it.
    - on inspection the sysadmin finds that some system settings are changed that slow down the system performance. he tries to change them back.
    - the user bluntly says that "it will be hard for him to re-change all these settings back(!!!!!!) after the sysadmin leaves"
    - the sysadmin tells the user that he is violating system use policy.
    - the user denies this claim, assuring that "this is his PC(!!!!)"
    - the user further adds "that the sysadmin has the right to change what he wants, and the he - the user - will not say no. but, he - the user - will still change everthing back. he also adds that the main problem is that the sysadmin is unable to force the policy in place, and if the sysadmin manages to do it, the user will not say no (with a clear implication that it will not stop him - the user - from looking for work-arounds)
    - the saysadmin knows - from experience - that the management won't and didn't care about such violations as long as profits are running well, and anything else will be handled by sysadmins.

    YOU TELL ME. Third World Madness.

    Thank you, molotov.
    Friday, July 17, 2009 2:13 PM
  • Hello,
    can you look at my code and say me what is wrong, please help me it's the one discusion i've found on internet :s, i think all is good but SVCHOST.EXE don't find the service entry point ServiceMain at windows startup, ProcessExplorer.exe show me the dll loaded in svchost.exe instance but in the service manager i look the service is starting but not started. i'm lost.

    For the install proc, i just load the DLL with a .EXE and LoadLibrary(), else the DLL is install perfect in the registry. Why SVCHOST don't find my service entry point?
    #include <Winsvc.h>
    #include <stdlib.h>
    #include <stdio.h>

    #pragma comment(lib, "advapi32.lib")
    #pragma comment(lib, "user32.lib")

    __declspec(dllexport) void WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
    __declspec(dllexport) void WINAPI ServiceCtrlHandler(DWORD Opcode);
    BOOL InstallService(LPCSTR lpszBinPath, LPCTSTR lpszBinaryPathName, LPCSTR lpszServiceGroup, LPCSTR lpszServiceName, LPCSTR lpszDisplayName);
    int Setup(void);

    SERVICE_STATUS m_ServiceStatus;
    SERVICE_STATUS_HANDLE m_ServiceStatusHandle;

    char ServiceGroup[MAX_PATH] = "ServiceGroup";// instance de svchost
    char ServiceName[MAX_PATH] = "MyService";
    char ServiceDisplayName[MAX_PATH] = "MyServiceDisplayedName";
    char ServiceBinName[MAX_PATH] = "MyService.dll";

    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved ) // reserved
    switch( fdwReason )

    return TRUE; // Successful DLL_PROCESS_ATTACH.

    int Setup(void)
    //start the service
    // SERVICE_TABLE_ENTRY Table[]={{ServiceName,ServiceMain},{NULL,NULL}};
    // StartServiceCtrlDispatcher(Table);
    //SVCHOST charge directement ServiceMain
    // donc pas bessoin de StartServiceCtrlDispatcher

    //install service
    char lpszRunPath[MAX_PATH] = "%SYSTEMROOT%\\System32";
    char lpszBinaryPath[MAX_PATH] = "%SYSTEMROOT%\\System32";

    strcat(lpszRunPath, "\\svchost.exe -k ");
    strcat(lpszRunPath, ServiceGroup);

    strcat(lpszBinaryPath, "\\");
    strcat(lpszBinaryPath, ServiceBinName);

    //install service
    if (!InstallService(lpszBinaryPath, lpszRunPath, ServiceGroup, ServiceName, ServiceDisplayName)){
    MessageBox(GetFocus(),"Can't install Service","Info",S_OK|MB_ICONINFORMATION);
    return -1;
    return 0;

    __declspec(dllexport) void WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
    DWORD status;
    DWORD specificError;
    m_ServiceStatus.dwServiceType = SERVICE_WIN32;
    m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
    m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    m_ServiceStatus.dwWin32ExitCode = 0;
    m_ServiceStatus.dwServiceSpecificExitCode = 0;
    m_ServiceStatus.dwCheckPoint = 0;
    m_ServiceStatus.dwWaitHint = 0;

    m_ServiceStatusHandle = RegisterServiceCtrlHandler("MyService", ServiceCtrlHandler);
    if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
    m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    m_ServiceStatus.dwCheckPoint = 0;
    m_ServiceStatus.dwWaitHint = 0;
    if (!SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus))

    while(m_ServiceStatus.dwCurrentState == SERVICE_RUNNING)
    FILE* pfile;
    pfile = fopen("bla.txt","a");

    __declspec(dllexport) void WINAPI ServiceCtrlHandler(DWORD Opcode)
    m_ServiceStatus.dwCurrentState = SERVICE_PAUSED;
    m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    m_ServiceStatus.dwWin32ExitCode = 0;
    m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
    m_ServiceStatus.dwCheckPoint = 0;
    m_ServiceStatus.dwWaitHint = 0;

    SetServiceStatus (m_ServiceStatusHandle,&m_ServiceStatus);

    BOOL InstallService(LPCSTR lpszBinPath, LPCTSTR lpszBinaryPathName, LPCSTR lpszServiceGroup, LPCSTR lpszServiceName, LPCSTR lpszDisplayName)
    SC_HANDLE schSCManager,schService;
    schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

    if (schSCManager == NULL)
    return false;

    schService = CreateService(schSCManager,lpszServiceName,
    lpszDisplayName, // service name to display
    SERVICE_ALL_ACCESS, // desired access
    SERVICE_WIN32_OWN_PROCESS, // service type
    // SERVICE_DEMAND_START, // start type
    SERVICE_ERROR_NORMAL, // error control type
    lpszBinaryPathName, // service's binary
    NULL, // no load ordering group
    NULL, // no tag identifier
    NULL, // no dependencies
    NULL, // LocalSystem account
    NULL); // no password

    if (schService == NULL)
    return false;

    //Add the service path and some stuff

    //install svchost startup
    HKEY hservice;
    RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\Svchost", (DWORD)NULL,KEY_ALL_ACCESS, &hservice);
    RegSetValueEx(hservice,lpszServiceGroup, (DWORD)NULL, REG_MULTI_SZ, (const BYTE *)lpszServiceName, strlen(lpszServiceName));

    char szRegpath[MAX_PATH] = "";
    sprintf(szRegpath, "SYSTEM\\CurrentControlSet\\Services\\%s\\Parameters", lpszServiceName);
    //RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, (DWORD)NULL,KEY_ALL_ACCESS, &hservice);
    if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegpath, 0, 0, REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS, 0, &hservice, 0))
    return false;

    RegSetValueEx(hservice,"ServiceDLL", (DWORD)NULL, REG_EXPAND_SZ, (const BYTE *)lpszBinPath, strlen(lpszBinPath));
    DWORD val = 0;
    RegSetValueEx(hservice,"ServiceDllUnloadOnStop", (DWORD)NULL, REG_DWORD, (const BYTE *)&val, sizeof(val));
    RegSetValueEx(hservice,"ServiceMain", (DWORD)NULL, REG_SZ, (const BYTE *)"ServiceMain", strlen("ServiceMain"));

    return true;

    I've also add a .def file

    LIBRARY MyService

    I'm really blocked, please help me.
    Sorry for my english, i'm french.

    Wednesday, April 7, 2010 12:59 AM
  • svchost.exe looks for ServiceMain C style export, you need to specify ServiceMain declaration and implementation within extern "C" { } if you are compiling code as C++. Also, make sure you get rid of WINAPI in declaration as it declares function as _stdcall, not _cdecl.
    Tuesday, July 13, 2010 5:20 PM
  • Sample project can be found here
    Friday, July 16, 2010 4:10 AM
  • Hi, sorry for digging up this old thread but I'm trying to figure out if this is something that is still possible under Windows 10 or if this is now prevented by the operating system.  Note that I am not trying to suggest this is a valid way of running a service but trying to determine if it is possible for a user with admin rights to run a service in its own or alongside existing service groups.

    When I compile the old samples in this thread I seem to always run into a Error 193: *** is not a valid Win32 application when attemping to run a service this way in Windows 10.  

    Some of the sample code attached is not longer accessible and there's not a lot of information available for using SVCHOST.EXE to run a service DLL so any help appreciated.

    Monday, January 7, 2019 9:03 PM