// ==================================================
// Сервис "Sample of simple service"
// Шаблон простейшего сервиса Windows NT
//
// (С) Фролов А.В., 1996
// Email: frolov@glas.apc.org
// ==================================================

#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

#include "small.h"

// -----------------------------------------------------
// Глобальные переменные
// -----------------------------------------------------

// Код ошибки
DWORD dwErrCode;

// Текущее состояние сервиса
SERVICE_STATUS ss;

// Идентификатор сервиса
SERVICE_STATUS_HANDLE ssHandle;

// -----------------------------------------------------
// Функция main
// Точка входа сервиса при его инициализации
// -----------------------------------------------------
void main(int agrc, char *argv[])
{
  // Таблица точек входа
  SERVICE_TABLE_ENTRY DispatcherTable[] =
  {
    {
      // Имя сервиса
      MYServiceName,
      
      // Функция main сервиса
      (LPSERVICE_MAIN_FUNCTION)ServiceMain
    },
    {
      NULL,
      NULL
    }

  };

  printf("Sample of simple service\n"
    "(C) A. Frolov, 1996, Email: frolov@glas.apc.org\n");

  // Запуск диспетчера
  if(!StartServiceCtrlDispatcher(DispatcherTable))
  {
    fprintf(stdout,
      "StartServiceCtrlDispatcher: Error %ld\n", 
      GetLastError());
    getch();
    return;
  }
}

// -----------------------------------------------------
// Функция ServiceMain
// Точка входа main сервиса при его инициализации
// -----------------------------------------------------
void WINAPI ServiceMain(DWORD argc, LPSTR *argv)
{
  // Регистрируем управляющую функцию сервиса
  ssHandle = 
    RegisterServiceCtrlHandler(MYServiceName, ServiceControl);

  if(!ssHandle)
    return;

  // Устанавливаем состояние сервиса
  
  // Сервис работает как отдельный процесс
  ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;

  // Код ошибки при инициализации и завершения сервиса
  // не используется
  ss.dwServiceSpecificExitCode = 0;

  // Начинаем запуск сервиса.
  // Прежде всего устанавливаем состояние ожидания
  // запуска сервиса
  ReportStatus(SERVICE_START_PENDING, NO_ERROR, 4000);
  
  // Вызываем функцию, которая выполняет все
  // необходимые инициализирующие действия
  //  ServiceStart(argc, argv);

  // После завершения инициализации устанавливаем
  // состояние работающего сервиса
  ReportStatus(SERVICE_RUNNING, NOERROR, 0);

  return;
}

// -----------------------------------------------------
// Функция ServiceControl
// Точка входа управляющей функции сервиса 
// -----------------------------------------------------
void WINAPI ServiceControl(DWORD dwControlCode)
{
  // Анализируем код команды и выполняем эту команду
  switch(dwControlCode)
  {
    // Команда остановки сервиса
    case SERVICE_CONTROL_STOP:
    {
      // Устанавливаем состояние ожидания остановки
      ss.dwCurrentState = SERVICE_STOP_PENDING;
      ReportStatus(ss.dwCurrentState, NOERROR, 0);

      // Выполняем остановку сервиса, вызывая функцию,
      // которая выполняет все необходимые для этого действия
      // ServiceStop();

      // Отмечаем состояние как остановленный сервис
      ReportStatus(SERVICE_STOPPED, NOERROR, 0);
      break;
    }

    // Определение текущего состояния сервиса
    case SERVICE_CONTROL_INTERROGATE:
    {
      // Возвращаем текущее состояние сервиса
      ReportStatus(ss.dwCurrentState, NOERROR, 0);
      break;
    }

    // В ответ на другие команды просто возвращаем
    // текущее состояние сервиса
    default:
    {
      ReportStatus(ss.dwCurrentState, NOERROR, 0);
      break;
    }
  }
}

// -----------------------------------------------------
// Функция ReportStatus
// Посылка состояния сервиса системе управления сервисами
// -----------------------------------------------------
void ReportStatus(DWORD dwCurrentState,
       DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
  // Счетчик шагов длительных операций
  static DWORD dwCheckPoint = 1;

  // Если сервис не находится в процессе запуска,
  // его можно остановить
  if(dwCurrentState == SERVICE_START_PENDING)
    ss.dwControlsAccepted = 0;
  else
    ss.dwControlsAccepted = SERVICE_ACCEPT_STOP;

  // Сохраняем состояние, переданное через
  // параметры функции
  ss.dwCurrentState  = dwCurrentState;
  ss.dwWin32ExitCode = dwWin32ExitCode;
  ss.dwWaitHint      = dwWaitHint;

  // Если сервис не работает и не остановлен, 
  // увеличиваем значение счетчика шагов
  // длительных операций
  if((dwCurrentState == SERVICE_RUNNING) ||
     (dwCurrentState == SERVICE_STOPPED))
    ss.dwCheckPoint = 0;
  else
    ss.dwCheckPoint = dwCheckPoint++;

  // Вызываем функцию установки состояния
  SetServiceStatus(ssHandle, &ss);
}
