El API de Windows proporciona un API para crear servicios y vamos a ver como se utiliza. Harbour tiene implementado un API para servicios desarrollado por Jose Luis Capel que no se corresponde a la arquitectura proporcionada por Windows. Leandro comentaba que funcionan en Harbour (Tim Stone los usa) pero que no funcionan con xHarbour.
Asi que vamos a ver como se implementan en Windows en primer lugar y vamos a comprobar que funcionan correctamente con Harbour y xHarbour.
servicio.prg
- Code: Select all Expand view
- #include "FiveWin.ch"
function Main()
Servicio()
return nil
#pragma BEGINDUMP
#include <windows.h>
#include <tchar.h>
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService();
HB_FUNC( SERVICIO )
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = _T("MiServicio");
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
StartServiceCtrlDispatcher(ServiceTable);
}
#pragma warn -8057
void ServiceMain(int argc, char** argv )
{
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler(_T("MiServicio"), (LPHANDLER_FUNCTION)ControlHandler);
if (InitService() == 0)
{
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hStatus, &ServiceStatus);
// Aquí va el bucle principal del servicio
while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
{
// Realiza las tareas del servicio
Sleep(1000);
}
}
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hStatus, &ServiceStatus);
}
void ControlHandler(DWORD request)
{
switch(request)
{
case SERVICE_CONTROL_STOP:
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hStatus, &ServiceStatus);
return;
case SERVICE_CONTROL_SHUTDOWN:
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hStatus, &ServiceStatus);
return;
default:
break;
}
SetServiceStatus(hStatus, &ServiceStatus);
}
int InitService()
{
// Inicialización del servicio
return 0;
}
#pragma ENDDUMP
Para construirlo desde FWH\samples hacemos:
Con Harbour:
buildh.bat servicio
Con xHarbour:
buildx.bat servicio
Una vez construido hay que registrar el servicio. Para eso es necesario abrir una ventana CMD de Windows en modo Administrador (Ctrl+Click desde el menu del CMD):
Primero se registra el servicio:
sc create servicio binPath=c:\fwh\samples\servicio.exe
[SC] CreateService CORRECTO
A continuación se ejecuta el servicio:
sc start servicio
Si todo ha ido bien veremos esto en pantalla:
NOMBRE_SERVICIO: servicio
TIPO : 10 WIN32_OWN_PROCESS
ESTADO : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
CÓD_SALIDA_WIN32 : 0 (0x0)
CÓD_SALIDA_SERVICIO: 0 (0x0)
PUNTO_COMPROB. : 0x0
INDICACIÓN_INICIO : 0x0
PID : 18316
MARCAS :
Para detener el servicio hacemos:
sc stop servicio ó
sc stop servicio -force
Para saber su estado mientras esta en uso hacemos:
sc query servicio
Para eliminar el servicio una vez parado:
sc delete servicio
Os ruego que lo probeis tanto en Harbour como en xHarbour. Aqui funciona bien con ambos.
Lo próximo es como saltar desde el código en C a Harbour, algo que es muy sencillo