/*++

Routine Description:

    This function is executed when a Stop command is sent to the service by SCM.
    It specifies actions to take when a service stops running.  In this code
    sample, OnStop logs a service-stop message to the Application log, and
    waits for the finish of the main service function.

    Be sure to periodically call ReportServiceStatus() with
    SERVICE_STOP_PENDING if the procedure is going to take a long time.

Arguments:

    VOID

Return Value:

    VOID

--*/
VOID
CSampleService::OnStop()
{
    //
    // Log a service stop message to the Application log.
    //
    WriteToEventLog(L"SampleService in OnStop", 
                    EVENTLOG_INFORMATION_TYPE);

    //
    // Indicate that the service is stopping and wait for the finish of the 
    // main service function (ServiceWorkerThread).
    //
    m_fStopping = TRUE;

    if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
    {
        throw GetLastError();
    }

    //
    // Clean up the context after the worker thread has finished.
    //
    CloseContext(m_Context);
}
Esempio n. 2
0
    /*
     * Function to start as Windows service
     * The calling party should specify their entry point as input parameter
     * Returns TRUE if the Service is started successfully
     */
BOOL
RunAsService (INT (*ServiceFunction) (INT, LPTSTR *))
{

  /*
   * Set the ServiceEntryPoint 
   */
  ServiceEntryPoint = ServiceFunction;

  /*
   * By default, mark as Running as a service 
   */
  g_fRunningAsService = TRUE;

  /*
   * Initialize ServiceTableEntry table 
   */
  ServiceTableEntry[0].lpServiceName = app_name_long;	/* Application Name */

  /*
   * Call SCM via StartServiceCtrlDispatcher to run as Service 
   * * If the function returns TRUE we are running as Service, 
   */
  if (StartServiceCtrlDispatcher (ServiceTableEntry) == FALSE)
    {
      g_fRunningAsService = FALSE;

      /*
       * Some other error has occurred. 
       */
      WriteToEventLog (EVENTLOG_ERROR_TYPE,
		       _T ("Couldn't start service - %s"), app_name_long);
    }
  return g_fRunningAsService;
}
/*++

Routine Description:

    The function executes when the system is shutting down. It
    calls the OnShutdown virtual function in which you can specify what
    should occur immediately prior to the system shutting down. If an error
    occurs, the error will be logged in the Application event log.

Arguments:

    VOID

Return Value:

    VOID

--*/
VOID
CServiceBase::Shutdown()
{
    try
    {
        //
        // Perform service-specific shutdown operations.
        //
        OnShutdown();

        //
        // Tell SCM that the service is stopped.
        //
        SetServiceStatus(SERVICE_STOPPED);
    }
    catch (DWORD Error)
    {
        //
        // Log the error.
        //
        WriteToErrorLog(L"Service Shutdown", Error);
    }
    catch (...)
    {
        //
        // Log the error.
        //
        WriteToEventLog(L"Service failed to shut down.", EVENTLOG_ERROR_TYPE);
    }
}
/*++

Routine Description:

    This function is executed when a Start command is sent to the
    service by the SCM or when the operating system starts (for a service
    that starts automatically). It specifies actions to take when the
    service starts. In this code sample, OnStart logs a service-start
    message to the Application log, and queues the main service function for
    execution in a thread pool worker thread.

    NOTE: A service application is designed to be long running. Therefore,
          it usually polls or monitors something in the system. The monitoring is
          set up in the OnStart method. However, OnStart does not actually do the
          monitoring. The OnStart method must return to the operating system after
          the service's operation has begun. It must not loop forever or block. To
          set up a simple monitoring mechanism, one general solution is to create
          a timer in OnStart. The timer would then raise events in your code
          periodically, at which time your service could do its monitoring. The
          other solution is to spawn a new thread to perform the main service
          functions, which is demonstrated in this code sample.

Arguments:

    Argc - The number of command line arguments

    Argv - The array of command line arguments

Return Value:

    VOID

--*/
VOID
CSampleService::OnStart(
    DWORD  Argc,
    PWSTR *Argv
    )
{
	__debugbreak();

    //
    // Log a service start message to the Application log.
    //
    WriteToEventLog(L"SampleService in OnStart", 
                    EVENTLOG_INFORMATION_TYPE);

    //
    // Set up any variables the service needs.
    //
    SetVariables();

    //
    // Set up the context, and register for notifications.
    //
    InitializeContext(&m_Context);

    //
    // Queue the main service function for execution in a worker thread.
    //
    CThreadPool::QueueUserWorkItem(&CSampleService::ServiceWorkerThread, this);
}
Esempio n. 5
0
/*++

Routine Description:

    Log an error message.

Arguments:

    Function - The function that gives the error

    Error    - The error code

Return Value:

    VOID

--*/
VOID
WriteToErrorLog(
    PWSTR Function,
    DWORD Error
    )
{
    WCHAR Message[260];

    StringCchPrintf(Message, ARRAYSIZE(Message),
                    L"%ws failed with error: 0x%08x", Function, Error);

    WriteToEventLog(Message, TRACE_LEVEL_ERROR);
}
/*++

Routine Description:

    This function starts the service.  It calls the OnStart virtual function
    in which you can specify the actions to take when the service starts.  If
    an error occurs during the startup, the error will be logged in the
    Application event log, and the service will be stopped.

Arguments:

    Argc - The number of command line arguments

    Argv - The array of command line arguments

Return Value:

    VOID

--*/
VOID
CServiceBase::Start(
    DWORD  Argc,
    PWSTR *Argv
)
{
    try
    {
        //
        // Tell SCM that the service is starting.
        //
        SetServiceStatus(SERVICE_START_PENDING);

        //
        // Perform service-specific initialization.
        //
        OnStart(Argc, Argv);

        //
        // Tell SCM that the service is started.
        //
        SetServiceStatus(SERVICE_RUNNING);
    }
    catch (DWORD Error)
    {
        //
        // Log the error.
        //
        WriteToErrorLog(L"Service Start", Error);

        //
        // Set the service status to be stopped.
        //
        SetServiceStatus(SERVICE_STOPPED, Error);
    }
    catch (...)
    {
        //
        // Log the error.
        //
        WriteToEventLog(L"Service failed to start.", EVENTLOG_ERROR_TYPE);

        //
        // Set the service status to be stopped.
        //
        SetServiceStatus(SERVICE_STOPPED);
    }
}
/*++

Routine Description:

    This function stops the service.  It calls the OnStop virtual
    function in which you can specify the actions to take when the service
    stops.  If an error occurs, the error will be logged in the Application
    event log, and the service will be restored to the original state.

Arguments:

    VOID

Return Value:

    VOID

--*/
VOID
CServiceBase::Stop()
{
    DWORD OriginalState = m_status.dwCurrentState;

    try
    {
        //
        // Tell SCM that the service is stopping.
        //
        SetServiceStatus(SERVICE_STOP_PENDING);

        //
        // Perform service-specific stop operations.
        //
        OnStop();

        //
        // Tell SCM that the service is stopped.
        //
        SetServiceStatus(SERVICE_STOPPED);
    }
    catch (DWORD Error)
    {
        //
        // Log the error.
        //
        WriteToErrorLog(L"Service Stop", Error);

        //
        // Set the orginal service status.
        //
        SetServiceStatus(OriginalState);
    }
    catch (...)
    {
        //
        // Log the error.
        //
        WriteToEventLog(L"Service failed to stop.", EVENTLOG_ERROR_TYPE);

        //
        // Set the orginal service status.
        //
        SetServiceStatus(OriginalState);
    }
}
/*++

Routine Description:

    The function resumes normal functioning after being paused if
    the service supports pause and continue. It calls the OnContinue virtual
    function in which you can specify the actions to take when the service
    continues. If an error occurs, the error will be logged in the
    Application event log, and the service will still be paused.

Arguments:

    VOID

Return Value:

    VOID

--*/
VOID
CServiceBase::Continue()
{
    try
    {
        //
        // Tell SCM that the service is resuming.
        //
        SetServiceStatus(SERVICE_CONTINUE_PENDING);

        //
        // Perform service-specific continue operations.
        //
        OnContinue();

        //
        // Tell SCM that the service is running.
        //
        SetServiceStatus(SERVICE_RUNNING);
    }
    catch (DWORD Error)
    {
        //
        // Log the error.
        //
        WriteToErrorLog(L"Service Continue", Error);

        //
        // Tell SCM that the service is still paused.
        //
        SetServiceStatus(SERVICE_PAUSED);
    }
    catch (...)
    {
        //
        // Log the error.
        //
        WriteToEventLog(L"Service failed to resume.", EVENTLOG_ERROR_TYPE);

        //
        // Tell SCM that the service is still paused.
        //
        SetServiceStatus(SERVICE_PAUSED);
    }
}
/*++

Routine Description:

    The function pauses the service if the service supports pause
    and continue. It calls the OnPause virtual function in which you can
    specify the actions to take when the service pauses. If an error occurs,
    the error will be logged in the Application event log, and the service
    will become running.

Arguments:

    VOID

Return Value:

    VOID

--*/
VOID
CServiceBase::Pause()
{
    try
    {
        //
        // Tell SCM that the service is pausing.
        //
        SetServiceStatus(SERVICE_PAUSE_PENDING);

        //
        // Perform service-specific pause operations.
        //
        OnPause();

        //
        // Tell SCM that the service is paused.
        //
        SetServiceStatus(SERVICE_PAUSED);
    }
    catch (DWORD Error)
    {
        //
        // Log the error.
        //
        WriteToErrorLog(L"Service Pause", Error);

        //
        // Tell SCM that the service is still running.
        //
        SetServiceStatus(SERVICE_RUNNING);
    }
    catch (...)
    {
        //
        // Log the error.
        //
        WriteToEventLog(L"Service failed to pause.", EVENTLOG_ERROR_TYPE);

        //
        // Tell SCM that the service is still running.
        //
        SetServiceStatus(SERVICE_RUNNING);
    }
}
Esempio n. 10
0
/*
** Name: WriteDTCerrToEventLog
**
** Description:
**      Decode the error return code into a message and
**      report to the Windows Event Log the error message list. 
**
*/
void WriteDTCerrToEventLog(HRESULT hr, char * t)
{
 char    message[512];
 char    workarea[256];
 char *  s;

 switch (hr)
 {
   case E_FAIL:
      s="rc=E_FAIL (General failure; Check the Windows Event Viewer for more information)";
      break;
   case E_INVALIDARG:
      s="rc=E_INVALIDARG (One or more of the parameters are NULL or invalid)";
      break;
   case E_NOINTERFACE:
      s="rc=E_NOINTERFACE (Unable to provide the requested interface)";
      break;
   case E_OUTOFMEMORY:
      s="rc=E_OUTOFMEMORY (Unable to allocate resources for the object)";
      break;
   case E_UNEXPECTED:
      s="rc=E_UNEXPECTED (An unexpected error occurred)";
      break;
   case E_POINTER:
      s="rc=E_POINTER (Invalid handle)";
      break;
   case XACT_E_CONNECTION_DOWN:
      s="rc=XACT_E_CONNECTION_DOWN (Lost connection with DTC Transaction Manager)";
      break;
   case XACT_E_TMNOTAVAILABLE:
      s="rc=XACT_E_TMNOTAVAILABLE (Unable to establish a connection with DTC (MS DTC service probably not started))";
      break;
   case XACT_E_NOTRANSACTION:
      s="rc=XACT_E_NOTRANSACTION (No transaction corresponding to ITRANSACTION pointer)";
      break;
   case XACT_E_CONNECTION_DENIED:
      s="rc=XACT_E_CONNECTION_DENIED (Transaction manager refused to accept a connection)";
      break;
   case XACT_E_LOGFULL:
      s="rc=XACT_E_LOGFULL (Transaction Manager has run out of log space)";
      break;
   case XACT_E_XA_TX_DISABLED:
      s="rc=XACT_E_XA_TX_DISABLED (Transaction Manager has disabled its support "
        "for XA transactions.  See MS KB article 817066 to enable XA and register "
        "\"caiiod35.dll\".)";
      break;
   default:
      s=workarea;
      wsprintf(s,"0x%8.8lX",(long)hr);
 }

 strcpy(message, t);
 if (hr != S_OK)
    {
     strcat(message, ";  ");
     strcat(message,s);   /* write return code message to errlog */
    }

 WriteToEventLog("Ingres ODBC", message);

 return;
}
Esempio n. 11
0
    /*
     * ServiceMain function.
     */
VOID WINAPI
ServiceMain (DWORD argc, LPTSTR argv[])
{
  SECURITY_ATTRIBUTES SecurityAttributes;
  unsigned threadId;

  /*
   * Input arguments
   */
  DWORD ArgCount = 0;
  LPTSTR *ArgArray = NULL;
  TCHAR szRegKey[512];
  HKEY hParamKey = NULL;
  DWORD TotalParams = 0;
  DWORD i;
  InputParams ThreadInputParams;

  /*
   * Build the Input parameters to pass to worker thread 
   */

  /*
   * SCM sends Service Name as first arg, increment to point
   * arguments user specified while starting control agent
   */

  /*
   * Read registry parameter 
   */
  ArgCount = 1;

  /*
   * Create registry key path 
   */
  _sntprintf (szRegKey, CountOf(szRegKey), _T("%s%s\\%s"),
	     _T ("SYSTEM\\CurrentControlSet\\Services\\"), app_name_long,
	     _T("Parameters"));
  if (RegOpenKeyEx
      (HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_ALL_ACCESS, &hParamKey) == ERROR_SUCCESS)
    {

      /*
       * Read startup configuration information 
       */
      /*
       * Find number of subkeys inside parameters 
       */
      if (RegQueryInfoKey (hParamKey, NULL, NULL, 0,
	   NULL, NULL, NULL, &TotalParams,
	   NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
	{
	  if (TotalParams != 0)
	    {
	      ArgCount += TotalParams;

	      /*
	       * Allocate memory to hold strings 
	       */
	      ArgArray = calloc(ArgCount, sizeof(ArgArray[0]));
              if (ArgArray == 0)
                {
                  WriteToEventLog (EVENTLOG_ERROR_TYPE,
		       _T ("Resource failure"));
                  return;
                }

	      /*
	       * Copy first argument 
	       */
	      ArgArray[0] = _tcsdup (argv[0]);
	      for (i = 1; i <= TotalParams; i++)
		{
                  DWORD dwErrorcode;
                  DWORD nSize;
                  DWORD nRegkeyType;
                  TCHAR *szValue;

		  /*
		   * Create Subkey value name 
		   */
		  _sntprintf (szRegKey, CountOf(szRegKey), _T("%s%d"), _T("Param"), i);

		  /*
		   * Query subkey.
		   */
		  nSize = 0;
		  dwErrorcode = RegQueryValueEx(hParamKey, szRegKey, NULL,
                                                &nRegkeyType, NULL, &nSize);
                  if (dwErrorcode == ERROR_SUCCESS) {
                    if (nRegkeyType == REG_SZ || nRegkeyType == REG_EXPAND_SZ) {
                      szValue = malloc(nSize + sizeof(szValue[0]));
                      if (szValue) {
		        dwErrorcode = RegQueryValueEx(hParamKey, szRegKey, NULL,
                                                      &nRegkeyType, (LPBYTE)szValue, &nSize);
                        if (dwErrorcode == ERROR_SUCCESS) {
                          szValue[nSize] = 0;
                          ArgArray[i] = szValue;
                        } else {
                          free(szValue);
                          WriteToEventLog(EVENTLOG_ERROR_TYPE, _T("Querying registry key %s failed: error code %ld"), szRegKey, dwErrorcode);
                        }
                      } else
                        WriteToEventLog(EVENTLOG_ERROR_TYPE, _T("Querying registry key %s failed: out of memory"), szRegKey);
                    } else
                      WriteToEventLog(EVENTLOG_ERROR_TYPE, _T("Type %ld of registry key %s is incorrect"), nRegkeyType, szRegKey);
                  } else
                    WriteToEventLog(EVENTLOG_ERROR_TYPE, _T("Querying registry key %s failed: error code %ld"), szRegKey, dwErrorcode);

                  if (!ArgArray[i]) {
                    TotalParams = ArgCount = i;
                    break;
                  }
		}
	    }
	}
      RegCloseKey (hParamKey);
    }
  if (ArgCount == 1)
    {

      /*
       * No startup args are given 
       */
      ThreadInputParams.Argc = argc;
      ThreadInputParams.Argv = argv;
    }

  else
    {
      ThreadInputParams.Argc = ArgCount;
      ThreadInputParams.Argv = ArgArray;
    }

  /*
   * Register Service Control Handler 
   */
  hServiceStatus = RegisterServiceCtrlHandler (app_name_long, ControlHandler);
  if (hServiceStatus == 0)
    {
      WriteToEventLog (EVENTLOG_ERROR_TYPE,
		       _T ("RegisterServiceCtrlHandler failed"));
      return;
    }

  /*
   * Update the service status to START_PENDING.
   */
  UpdateServiceStatus (SERVICE_START_PENDING, NO_ERROR, SCM_WAIT_INTERVAL);

  /*
   * Start the worker thread, which does the majority of the work .
   */
  TRY
  {
    if (SetSimpleSecurityAttributes (&SecurityAttributes) == FALSE)
      {
	WriteToEventLog (EVENTLOG_ERROR_TYPE,
			 _T ("Couldn't init security attributes"));
	LEAVE;
      }
    hServiceThread =
      (void *) _beginthreadex (&SecurityAttributes, 0,
			       ThreadFunction,
			       (void *) &ThreadInputParams, 0, &threadId);
    if (hServiceThread == NULL)
      {
	WriteToEventLog (EVENTLOG_ERROR_TYPE, _T ("Couldn't start worker thread"));
	LEAVE;
      }

    /*
     * Set service status to SERVICE_RUNNING.
     */
    UpdateServiceStatus (SERVICE_RUNNING, NO_ERROR, SCM_WAIT_INTERVAL);

    /*
     * Wait until the worker thread finishes.
     */
    WaitForSingleObject (hServiceThread, INFINITE);
  }
  FINALLY
  {
    /*
     * Release resources 
     */
    UpdateServiceStatus (SERVICE_STOPPED, NO_ERROR, SCM_WAIT_INTERVAL);
    if (hServiceThread)
      CloseHandle (hServiceThread);
    FreeSecurityAttributes (&SecurityAttributes);

    /*
     * Free allocated argument list 
     */
    if (ArgCount > 1 && ArgArray != NULL)
      {
	/*
	 * Free all strings 
	 */
	for (i = 0; i < ArgCount; i++)
	  {
	    free (ArgArray[i]);
	  }
	free (ArgArray);
      }
  }
}
Esempio n. 12
0
    /*
     * The ServiceMain function to start service.
     */
VOID WINAPI
ServiceMain (DWORD argc, LPTSTR argv[])
{
  SECURITY_ATTRIBUTES SecurityAttributes;
  DWORD dwThreadId;

  /*
   * Input Arguments to function startup 
   */
  DWORD ArgCount = 0;
  LPTSTR *ArgArray = NULL;
  TCHAR szRegKey[512];
  TCHAR szValue[128];
  DWORD nSize;
  HKEY hParamKey = NULL;	/* To read startup parameters */
  DWORD TotalParams = 0;
  DWORD i;
  InputParams ThreadInputParams;

  /*
   * Build the Input parameters to pass to worker thread 
   */

  /*
   * SCM sends Service Name as first arg, increment to point
   * arguments user specified while starting contorl agent
   */

  /*
   * Read registry parameter 
   */
  ArgCount = 1;

  /*
   * Create Registry Key path 
   */
  _snprintf (szRegKey, sizeof(szRegKey), "%s%s\\%s",
	     _T ("SYSTEM\\CurrentControlSet\\Services\\"), app_name,
	     "Parameters");
  if (RegOpenKeyEx
      (HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_ALL_ACCESS, &hParamKey) == ERROR_SUCCESS)
    {

      /*
       * Read startup Configuration information 
       */
      /*
       * Find number of subkeys inside parameters 
       */
      if (RegQueryInfoKey (hParamKey, NULL, NULL, 0,
	   NULL, NULL, NULL, &TotalParams,
	   NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
	{
	  if (TotalParams != 0)
	    {
	      ArgCount += TotalParams;

	      /*
	       * Allocate memory to hold strings 
	       */
	      ArgArray = (LPTSTR *) malloc (sizeof (LPTSTR) * ArgCount);

	      /*
	       * Copy first argument 
	       */
	      ArgArray[0] = _tcsdup (argv[0]);
	      for (i = 1; i <= TotalParams; i++)
		{

		  /*
		   * Create Subkey value name 
		   */
		  _snprintf (szRegKey, sizeof(szRegKey), "%s%d", "Param", i);

		  /*
		   * Set size 
		   */
		  nSize = 128;
		  RegQueryValueEx (hParamKey, szRegKey, 0, NULL,
				   (LPBYTE) & szValue, &nSize);
		  ArgArray[i] = _tcsdup (szValue);
		}
	    }
	}
      RegCloseKey (hParamKey);
    }
  if (ArgCount == 1)
    {

      /*
       * No statup agrs are given 
       */
      ThreadInputParams.Argc = argc;
      ThreadInputParams.Argv = argv;
    }

  else
    {
      ThreadInputParams.Argc = ArgCount;
      ThreadInputParams.Argv = ArgArray;
    }

  /*
   * Register Service Control Handler 
   */
  hServiceStatus = RegisterServiceCtrlHandler (app_name, ControlHandler);
  if (hServiceStatus == 0)
    {
      WriteToEventLog (EVENTLOG_ERROR_TYPE,
		       _T ("RegisterServiceCtrlHandler failed"));
      return;
    }

  /*
   * Update the service status to START_PENDING 
   */
  UpdateServiceStatus (SERVICE_START_PENDING, NO_ERROR, SCM_WAIT_INTERVAL);

  /*
   * Spin of worker thread, which does majority of the work 
   */
  TRY
  {
    if (SetSimpleSecurityAttributes (&SecurityAttributes) == FALSE)
      {
	WriteToEventLog (EVENTLOG_ERROR_TYPE,
			 _T ("Couldn't init security attributes"));
	LEAVE;
      }
    hServiceThread =
      (void *) _beginthreadex (&SecurityAttributes, 0,
			       ThreadFunction,
			       (void *) &ThreadInputParams, 0, &dwThreadId);
    if (hServiceThread == NULL)
      {
	WriteToEventLog (EVENTLOG_ERROR_TYPE, _T ("Couldn't start worker thread"));
	LEAVE;
      }

    /*
     * Set Service Status to Running 
     */
    UpdateServiceStatus (SERVICE_RUNNING, NO_ERROR, SCM_WAIT_INTERVAL);

    /*
     * Wait for termination event and worker thread to
     * * spin down.
     */
    WaitForSingleObject (hServiceThread, INFINITE);
  }
  FINALLY
  {
    /*
     * Release resources 
     */
    UpdateServiceStatus (SERVICE_STOPPED, NO_ERROR, SCM_WAIT_INTERVAL);
    if (hServiceThread)
      CloseHandle (hServiceThread);
    FreeSecurityAttributes (&SecurityAttributes);

    /*
     * Delete allocated argument list 
     */
    if (ArgCount > 1 && ArgArray != NULL)
      {
	/*
	 * Delete all strings 
	 */
	for (i = 0; i < ArgCount; i++)
	  {
	    free (ArgArray[i]);
	  }
	free (ArgArray);
      }
  }
}