Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

MFS Service Manger

0.00/5 (No votes)
8 Dec 2004 1  
A fully functional replica of Windows Service Manager, with some extra features like Enumeration, Deletion and Updation of the Services.

Sample Application

Introduction

Hello fellow CPians,

Back again with new application .I think, you wanna know that what exactly this application is doing. This application can enumerate all window services, provide support for Starting, Stopping and Restarting, provide support for switching the Startup Type between Automatic, Manual And Disable, changing the path of Services and last but not the least and most dangerous one Uninstalling the Service.

"I Request, Please handle this Option with Care (UnInstalling One), if this action is executed once, there is no chance of rollback or you know how to install that particular service".

Background

Now let's take a look at what MSDN says about services ---

�A service application conforms to the interface rules of the Service Control Manager (SCM). It can be started automatically at system boot, by a user through the Services control panel applet, or by an application that uses the service functions, Services Start Running.

A driver service conforms to the device driver protocols. It is similar to a service application, but it does not interact with the SCM. For simplicity, the term service refers to a service application in this overview. "

This is the list of all the APIs I have used to Enumerate, Control, Edit and Delete service.

A Little Description About These APIs

  • OpenSCManager

      SC_HANDLE OpenSCManager
      (
         LPCTSTR lpMachineName,   // computer name
    
         LPCTSTR lpDatabaseName,  // SCM database name
    
         DWORD dwDesiredAccess    // access type 
    
      );

    A little description about OpenSCManager

    This API is used to open the database of service on local computer. Yeah, you can open it to use the service database on remote computer (but that required proper network authorization). You need to open the service manager to perform each service related task.

  • OpenService

      SC_HANDLE OpenService
      (
         SC_HANDLE hSCManager,  // handle to SCM database
    
         LPCTSTR lpServiceName, // service name
    
         DWORD dwDesiredAccess  // access
    
      );

    A little description about OpenService

    This API is used to open particular service from service database. This API is used after a successful call of OpenSCManager API.

  • EnumServiceStatus

      BOOL EnumServicesStatus
      (
        SC_HANDLE hSCManager,             // handle to SCM database
    
        DWORD dwServiceType,              // service type
    
        DWORD dwServiceState,             // service state
    
        LPENUM_SERVICE_STATUS lpServices, // status buffer
    
        DWORD cbBufSize,                  // size of status buffer
    
        LPDWORD pcbBytesNeeded,           // buffer size needed
    
        LPDWORD lpServicesReturned,       // number of entries returned
    
        LPDWORD lpResumeHandle            // next entry 
    
      );

    A little description about EnumServiceStatus

    As the name indicates, this API is used to enumerate the services depending upon function call specifications:

    • Second parameter - which type of service you want to enumerate.
    • Third parameter - what type of service is returned, i.e. running or stopped services.
    • Fourth parameter - buffer of ENUM_SERVICE_STATUS ( which will bring back all the Services).
    • Fifth parameter - will hold total buffer size of fourth parameter
    • Sixth parameter - contain total byte of memory needed to retrieve all the service with necessary details (i.e. ENUM_SERVICE_STATUS)
    • Seventh parameter - contains number of services returned after successful call of above API.
    • Eighth parameter - is returned with resume handle if the buffer is not enough to hold the all the services present in system.
  • QueryServiceConfig

    BOOL QueryServiceConfig
    (
      SC_HANDLE hService,                     // handle to service
    
      LPQUERY_SERVICE_CONFIG lpServiceConfig, // buffer
    
      DWORD cbBufSize,                        // size of buffer
    
      LPDWORD pcbBytesNeeded                  // bytes needed
    
    );

    A little description about QueryServieConfig

    This API query current status of service, where the first parameter is handle obtained from OpenService and the second parameter is structure, which will return with information.

  • StartService

    BOOL StartService
    (
      SC_HANDLE hService,            // handle to service
    
      DWORD dwNumServiceArgs,        // number of arguments
    
      LPCTSTR* lpServiceArgVectors   // array of arguments
    
    );

    A little description about StartService

    As the name suggests that it will Start service whose handle is going to pass in the first parameter, second parameter inputs the number of arguments for service to be passed in parameter three and third parameter is an array of string argument for service.

  • ControlService

    BOOL ControlService
    (
      SC_HANDLE hService,               // handle to service
    
      DWORD dwControl,                  // control code
    
      LPSERVICE_STATUS lpServiceStatus  // status information
    
    );

    A little description about ControlService

    As the name suggests that it will Control service whose handle is going to pass in the First Parameter, Second Parameter specifies the requested control code, most common are SERVICE_CONTROL_STOP, SERVICE_CONTROL_PAUSE, SERVICE_CONTROL_CONTINUE and third Parameter returns current status structure of service.

  • DeleteService

    BOOL DeleteService
    (
      SC_HANDLE hService   // handle to service
    
    );

    A little description about DeleteService

    As the name suggests that it will Delete service whose handle is going to be passed in the First Parameter.

  • ChangeServiceConfig

    BOOL ChangeServiceConfig
    (
      SC_HANDLE hService          // handle to service
    
      DWORD dwServiceType,        // type of service
    
      DWORD dwStartType,          // when to start service
    
      DWORD dwErrorControl,       // severity of start failure
    
      LPCTSTR lpBinaryPathName,   // service binary file name
    
      LPCTSTR lpLoadOrderGroup,   // load ordering group name
    
      LPDWORD lpdwTagId,          // tag identifier
    
      LPCTSTR lpDependencies,     // array of dependency names
    
      LPCTSTR lpServiceStartName, // account name
    
      LPCTSTR lpPassword,         // account password
    
      LPCTSTR lpDisplayName       // display name
    
    );

    A little description about ChangeServiceConfig

    As name indicates, this API is used to Change the service Configuration. I am going to discuss commonly used parameter of this API.

    • First Parameter - Indicates the handle of service.
    • Second parameter - If you want to change service type.
    • Third parameter - For changing startup type.
    • Fifth Parameter - For changing binary path of executable.
    • Ninth parameter - Indicates in which user, you want to run the service.
    • Tenth parameter - Password of account specified in ninth paragraph.
    • Eleventh Parameter - Used to change the display name of the service.

Using the code

I will Explain Everything now, with the help of code snippet.

Here is list of possible common functions that can be performed from above APIs.

I know more combinations possible, but I am stating those only which is going to provide with MFS Service Manager TM :D

  1. For obtaining the main ScManager handle.
            
    SC_HANDLE ScManager; 
    //here I am opening the service manager using OpenScManager API call 
    
    
    ScManager=::OpenSCManager(NULL,NULL,SC_MANAGER_ENUMERATE_SERVICE|GENERIC_READ); 
    
    //check that whether we able to connect with local computer service 
    
    //database or Not
    
    //Remember if we Use SC_MANAGER_ALL_ACCESS, we need Administrator
    
    //right for that.
    
    //with using SC_MANAGER_ENUMERATE_SERVICE|GENERIC_READ it guranteed 
    
    //that it going to open for each user 
    
            
    if(ScManager==NULL) 
    {
       MessageBox("Error Opening Service Mgr"); 
       return; 
    }
  2. For obtaining particular service handle.
    SC_HANDLE ScService;
    //Open Service
    
    if((ScService=::OpenService(
         ScManager,"any service Name",SERVICE_ALL_ACCESS))==NULL)
    {
         ::CloseHandle(ScManager);
         MessageBox("Problem in opening service");
    }
  3. For enumerating the service.
    ENUM_SERVICE_STATUS EnService[512]; //service Enumeration Structure
    
    DWORD cbBufSize=512*sizeof(ENUM_SERVICE_STATUS); // size of status buffer
    
    DWORD lpServicesReturned; 
    DWORD pcbBytesNeeded; // buffer size needed
    
    DWORD lpResumeHandle       
    DWORD lpResumeHandle=0; // next entry 
    
    
    //Assuming that you got the Handle if SCManager from OpenSCManager
    
    
    if(::EnumServicesStatus(
      ScManager,//Service manager Handle
    
      SERVICE_WIN32, //Service type To be retrieved
    
      SERVICE_STATE_ALL, //
    
      EnService, // Buffer 
    
      cbBufSize, //Buffer Size
    
      &pcbBytesNeeded, //number of Bytes Needed
    
      &lpServicesReturned, //number of Service Return
    
      &lpResumeHandle //Resume Handle if any
    
    
      )= =0)
      {
        MessageBox("Error Querrying Service Mgr"); 
        return; 
      }
  4. Checking state of service.
    // now check the state of each service 
    
    for(int i=0;i< INT ( LPSERVICESRETURNED);i++) 
    {
      MessageBox(EnService[i].lpServiceName,"service Name"); 
      MessageBox(EnService[i].lpDisplayName,"Display Name");
    
    //the ENUM_SERVICE_STATUS third parameter 
    
    //contain the status of each service 
    
    
    switch(EnService[i].ServiceStatus.dwCurrentState)
     {
        case SERVICE_PAUSED: //service in paused state
    
        case SERVICE_RUNNING: // The service is running.
    
        case SERVICE_STOPPED:// The service is stopped 
    
        case SERVICE_START_PENDING: // The service is starting 
    
        case SERVICE_STOP_PENDING : // The service is stopped 
    
        default: //unknown state
    
     }
  5. For starting the service.
    //assuming that ScService contain Vaild Handle after 
    
    //Successful call of OpenService
    
    
    if(::StartService(ScService,0,NULL)==0) 
    { 
       //preparing Error 
    
       Variable MessageBox("Error Starting Service"); 
       return; 
    }
  6. & 7. For pausing and stopping service.
    //assuming that ScService contain Vaild Handle after 
    
    //Successful call of OpenService
    
    //For Pausing Service pass SERVICE_CONTROL_PAUSE in 
    
    //Second Parameter 
    
    if(::ControlService(ScService,SERVICE_CONTROL_STOP,&stt)==0) 
    { 
      //IF Error Occurs 
    
      MessageBox("Error: Unable to Stop Service"); 
      return; 
    }
  1. Updating the path of service.
    //assuming that ScService contain Vaild Handle after 
    
    //Successful call of OpenService
    
    //Here is Code Snipet for getting  Path
    
    
    LPQUERY_SERVICE_CONFIG lpqscBuf;
    DWORD dwBytesNeeded;
    //Allocate the necessary memory to Query Structure ,so
    
    // that we can get all the Needed Data without any Buffer Problem
    
    
    lpqscBuf = (LPQUERY_SERVICE_CONFIG) LocalAlloc( LPTR,4096);
    
    if (lpqscBuf == NULL)
    {
      MessageBox("Memory Allocation error");
      return;
    }
    
    // Get     theconfiguration information.
    
    //Call the real function,that will query
    
    //service for its path etc.
    
    
     if (!QueryServiceConfig(
         
          
          ScService,
          lpqscBuf,
          4096,
          &dwBytesNeeded)
        )
      {
         MessageBox("Error in querying Services");
         return;
      }
    
    MessageBox(lpqscBuf->lpBinaryPathName ,"Current Binary path");
    
    //Here to Code Snippet for Updating Path
    
    
    if(::ChangeServiceConfig(
       ScService,
       SERVICE_NO_CHANGE,
       SERVICE_NO_CHANGE,
       SERVICE_NO_CHANGE,
      
      
       NEW PATH,//path to be changed
    
       NULL,NULL,NULL,NULL,NULL,NULL))
      {
         MessageBox("Service PathChanged",
             "MFS SERVICEMGR",MB_OK|MB_ICONINFORMATION);
      }
      else
      {
         MessageBox("Error In ChangingPath","MFS SERVICE MGR",MB_OK|MB_ICONSTOP);
      }
  2. For deleting the service.
    //assuming that ScService contain Vaild Handle 
    
    //after Successful call of OpenService
    
    
    if(::DeleteService(ScService)==0)
    { //Showing Message
    
      MessageBox("Error Deleting Service");
      return;
    }
    else
    {
       MessageBox("Service Marked For Deletion\nDeleted After Computer Restart");
    }

History

  • Version 1.0

    First Release.

  • Version 1.1

    Updated the binary path option to edit the service executable path as asked by my friend Suhredayan and other bug fixes.

Special Thanks

  • My Parents
  • My friend Amit Mehta
  • Mr. Suhredayan for demanding newer version of this application.
  • The Code Project for providing platform for emerging Programmers.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here