Remotely Start a System Service

RemStart illustrates how to remotely start a Windows System Service via a network connection. This allows you to set the service for "Manual" startup so that doesn't use system resources (CPU cycles, memory, etc.) until you need them. Programmatically, It also assures that the remote System Service is up and active before you try to access it.

RemStart.h

/********************************************************************************
* Copyright (c) 2010 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
********************************************************************************/

// Header File for the "Remotely Start a System Service" Code

#ifndef _REMSTART_H_
#define _REMSTART_H_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifdef __cplusplus
extern "C" {
#endif   // __cplusplus

unsigned long RemStart ( char * szServiceName, char * szComputerName = NULL );

#ifdef __cplusplus
}
#endif   // __cplusplus

#endif // _REMSTART_H_

ErrorText.h

/********************************************************************************
* Copyright (c) 2010 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
********************************************************************************/

// Header File for the "GetErrorText" Code

#ifndef _ERRORTEXT_H_
#define _ERRORTEXT_H_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifdef __cplusplus
extern "C" {
#endif   // __cplusplus

char * GetErrorText ( unsigned long dwErrorCode, char * szErrorText, size_t cbErrorText );

#ifdef __cplusplus
}
#endif   // __cplusplus

#endif // _ERRORTEXT_H_

RemStart.cpp

/********************************************************************************
* Copyright (c) 2010 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
********************************************************************************/

// RemStart.cpp : Remotely Start a System Service

#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers

#include <WINDOWS.H>

#include "RemStart.h"

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

unsigned long RemStart ( char * szServiceName, char * szRemoteComputerName )

   {
   SC_HANDLE      schSCManager                                    = NULL;
   SC_HANDLE      schService                                      = NULL;
   SERVICE_STATUS ssStatus                                        = { 0LU };

   char           szComputerName [ MAX_COMPUTERNAME_LENGTH + 1 ]  = "\\\\";

   // Determine the Computer Name

   if ( szRemoteComputerName )
      {
      strcat ( szComputerName, szRemoteComputerName );
      }
   else
      {
      char           szHostName  [ MAX_COMPUTERNAME_LENGTH + 1 ]  = { 0 };
      unsigned long  cbHostName                                   = sizeof szHostName;

      GetComputerName ( szHostName, &cbHostName );

      strcat ( szComputerName, szHostName );
      }

   if ( ( schSCManager = OpenSCManager ( szComputerName, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT ) ) == NULL )
      return GetLastError();

   if ( ( schService = OpenService ( schSCManager, szServiceName, SERVICE_ALL_ACCESS ) ) == NULL )
      {
      CloseServiceHandle ( schSCManager );

      return GetLastError();
      }

   if ( ! StartService ( schService, 0, NULL ) )
      {
      DWORD dwErrorCode = GetLastError();

      CloseServiceHandle ( schService );
      CloseServiceHandle ( schSCManager );

      return dwErrorCode == ERROR_SERVICE_ALREADY_RUNNING ? ERROR_SUCCESS : dwErrorCode;
      }

   for (;;)
      {
      Sleep ( 100LU );

      if ( ! QueryServiceStatus ( schService, &ssStatus ) )
         return GetLastError();

      if ( ssStatus.dwCurrentState != SERVICE_START_PENDING )
         break;
      }

   if ( schService && ! CloseServiceHandle ( schService ) )
      return GetLastError();

   if ( schSCManager && ! CloseServiceHandle ( schSCManager ) )
      return GetLastError();

   return ERROR_SUCCESS;

   }  // unsigned long RemStart ( char * szServiceName, char * szRemoteComputerName )

ErrorText.cpp

/********************************************************************************
* Copyright (c) 2010 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
********************************************************************************/

// ErrorText.cpp : Get the Text Message Associated with an Error Code

#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers

#include <WINDOWS.H>

#include "ErrorText.h"

char * GetErrorText ( unsigned long dwErrorCode, char * szErrorText, size_t cbErrorText )

   {
   static const unsigned long dwFlags        = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK;
   static const unsigned long dwLanguageId   = MAKELANGID ( LANG_ENGLISH, SUBLANG_ENGLISH_US );

   // Initially Zero Out the Entire Buffer

   memset ( szErrorText, 0, cbErrorText );

   // Retrieve a Message from the System Message Table

   FormatMessage (

      dwFlags,       // Source and Processing Options
      NULL,          // Source Ignored - We're Getting Message from System
      dwErrorCode,   // Message ID
      dwLanguageId,  // Message Language
      szErrorText,   // Address of Buffer Pointer
      cbErrorText,   // Maximum Buffer Size
      NULL           // No Other Arguments

   );

   return szErrorText;

   }  // unsigned long GetErrorText ( unsigned long dwErrorCode, char * szErrorText, size_t cbErrorText )

Try.cpp

/********************************************************************************
* Copyright (c) 2010 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
********************************************************************************/

// Try.cpp : Demonstrate how to Remotely Start a System Service

// CL -MT Try.cpp RemStart.cpp ErrorText.cpp -FeRemStart.exe

#include <STDIO.H>

#include "Remstart.h"
#include "ErrorText.h"

int main ( int argc, char * argv [], char * /* envp */ [] )

   {
   char * szServiceName    = argc > 1 ? argv [ 1 ] : "TrySvc"; // The System Service Name
   char * szComputerName   = argc > 2 ? argv [ 2 ] : NULL;     // The Computer Name

   // Process a Help Request

   if ( ( szServiceName [ 0 ] == '/' || szServiceName [ 0 ] == '-' ) && szServiceName [ 1 ] == '?' )
      {
      fprintf ( stdout, "RemStart [ <syssvc> [ <computer> ] ]\n" );

      return 1;
      }

   // Start the (Remote) System Service

   if ( unsigned long ulResult = RemStart ( szServiceName, szComputerName ) )
      {
      char szErrorText [ 128 ] = { 0 };   // The Text Error Message

      fprintf ( stderr, "RemStart(%s,%s):  [%lu] %s\n\a", szServiceName, szComputerName ? szComputerName : "NULL", ulResult, GetErrorText ( ulResult, szErrorText, sizeof szErrorText ) );

      return 2;
      }

   // Return Success

   fprintf ( stdout, "Success!\n" );

   return 0;

   }  // int main ( int argc, char * argv [], char * envp [] )