Page 1 of 2
Creando Servicios con Harbour y xHarbour
Posted: Sat Sep 14, 2024 6:03 am
by Antonio Linares
Este tema nos quedó pendiente en el webinar y os prometí desarrollarlo
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
#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
Re: Creando Servicios con Harbour y xHarbour
Posted: Sat Sep 14, 2024 6:15 am
by Antonio Linares
Observaciones al uso de los servicios. Esto lo vimos en el webinar por encima. Aqui os lo detallo:
Existen varias diferencias importantes entre una aplicación normal de Windows y un servicio de Windows.
Interfaz de usuario:
Aplicación normal: Generalmente tiene una interfaz gráfica de usuario (GUI) con la que el usuario puede interactuar directamente.
Servicio: No tiene interfaz gráfica. Funciona en segundo plano sin interacción directa del usuario.
Inicio y ejecución:
Aplicación normal: Se inicia manualmente por el usuario o al arrancar el sistema si está configurada para ello.
Servicio: Puede configurarse para iniciarse automáticamente al arrancar el sistema, incluso antes de que cualquier usuario inicie sesión.
Sesión de usuario:
Aplicación normal: Se ejecuta en el contexto de la sesión del usuario que la inició.
Servicio: Puede ejecutarse incluso cuando ningún usuario ha iniciado sesión en el sistema.
Control:
Aplicación normal: El usuario la controla directamente a través de su interfaz.
Servicio: Se controla a través del Administrador de Control de Servicios (SCM) de Windows, usando herramientas como 'services.msc' o comandos como 'sc.exe’.
Privilegios:
Aplicación normal: Generalmente se ejecuta con los privilegios del usuario que la inició.
Servicio: A menudo se ejecuta con privilegios elevados del sistema, lo que le permite realizar tareas que requieren más permisos.
Estructura del código:
Aplicación normal: Tiene un punto de entrada main() estándar y un bucle de mensajes para la GUI si es una aplicación con ventanas.
Servicio: Requiere funciones específicas como ServiceMain() y ServiceCtrlHandler() para interactuar con el SCM.
Interacción con el sistema:
Aplicación normal: Interactúa principalmente con el usuario y puede tener acceso limitado a recursos del sistema.
Servicio: Diseñado para interactuar con el sistema operativo y otros servicios, a menudo realizando tareas críticas del sistema.
Ciclo de vida:
Aplicación normal: Típicamente se inicia, realiza su tarea y termina cuando el usuario la cierra.
Servicio: Diseñado para ejecutarse continuamente y manejar eventos como inicio, parada, pausa y continuación.
Recuperación ante fallos:
Aplicación normal: Si falla, generalmente requiere que el usuario la reinicie manualmente.
Servicio: Windows puede configurarse para reiniciar automáticamente un servicio si falla.
Desarrollo y depuración:
Aplicación normal: Relativamente sencilla de desarrollar y depurar con herramientas estándar.
Servicio: Puede ser más complejo de desarrollar y depurar debido a su naturaleza de fondo y la interacción con el SCM.
Estas diferencias hacen que los servicios sean ideales para tareas que necesitan ejecutarse continuamente en segundo plano, como servidores web, sistemas de base de datos, o tareas de mantenimiento del sistema, mientras que las aplicaciones normales son más adecuadas para tareas que requieren interacción directa del usuario.
Re: Creando Servicios con Harbour y xHarbour
Posted: Sat Sep 14, 2024 3:19 pm
by wilsongamboa
Buenos dias
Antonio obtengo esto
Warning W8065 servicio.prg 46: Call to function 'InitService' with no prototypein function ServiceMain
*** 1 errors in Compile ***
* Linking errors *
con el ultimo fwh que nos diste en webminar
saludos
Re: Creando Servicios con Harbour y xHarbour
Posted: Sat Sep 14, 2024 3:27 pm
by Antonio Linares
Wilson,
Que compilador de C estás usando ? Harbour ó xHarbour ?
Aqui lo he probado con bcc77 32 bits, Harbour y xHarbour, sin ningún warning o error:
┌────────────────────────────────────────────────────────────────────────────┐
│ FiveWin for Harbour 24.07 - Jul. 2024 Harbour development power │▄
│ (c) FiveTech 1993-2024 for Microsoft Windows 9X/NT/200X/ME/XP/Vista/7/8/10 │█
└────────────────────────────────────────────────────────────────────────────┘█
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
Compiling...
Harbour 3.2.0dev (r2403071241)
Copyright (c) 1999-2021,
https://harbour.github.io/
Compiling 'servicio.prg' and generating preprocessed output to 'servicio.ppo'...
Lines 5108, Functions/Procedures 1
Generating C source output to 'servicio.c'... Done.
Embarcadero C++ 7.70 for Win32 Copyright (c) 1993-2023 Embarcadero Technologies, Inc.
servicio.c:
Turbo Incremental Link 6.97 Copyright (c) 1997-2022 Embarcadero Technologies, Inc.
* Application successfully built *
┌────────────────────────────────────────────────────────────────────────────┐
│ FiveWin for xHarbour 24.07 - Jul. 2024 Harbour development power │▄
│ (c) FiveTech 1993-2024 for Microsoft Windows 9X/NT/200X/ME/XP/Vista/7/8/10 │█
└────────────────────────────────────────────────────────────────────────────┘█
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
Compiling...
xHarbour 1.3.1 Intl. (SimpLex) (Build 20240108)
Copyright 1999-2023,
http://www.xharbour.org http://www.harbour-project.org/
Compiling 'servicio.prg' and generating preprocessed output to 'servicio.ppo'...
Generating C source output to 'servicio.c'...
Done.
Lines 9, Functions/Procedures 1, pCodes 15
Embarcadero C++ 7.70 for Win32 Copyright (c) 1993-2023 Embarcadero Technologies, Inc.
servicio.c:
Turbo Incremental Link 6.97 Copyright (c) 1997-2022 Embarcadero Technologies, Inc.
* Application successfully built *
Re: Creando Servicios con Harbour y xHarbour
Posted: Sat Sep 14, 2024 5:16 pm
by wilsongamboa
Code: Select all | Expand
┌────────────────────────────────────────────────────────────────────────────┐
│ FiveWin for Harbour 24.07 - Jul. 2024 Harbour development power │▄
│ (c) FiveTech 1993-2024 for Microsoft Windows 9X/NT/200X/ME/XP/Vista/7/8/10 │█
└────────────────────────────────────────────────────────────────────────────┘█
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
Compiling...
Harbour 3.2.0dev (r2407221137)
Copyright (c) 1999-2021, https://harbour.github.io/
Compiling 'servicio.prg' and generating preprocessed output to 'servicio.ppo'..
Lines 5105, Functions/Procedures 1
Generating C source output to 'servicio.c'... Done.
Embarcadero C++ 7.70 for Win32 Copyright (c) 1993-2023 Embarcadero Technologies Inc.
servicio.c:
Warning W8065 servicio.prg 46: Call to function 'InitService' with no prototypein function ServiceMain
*** 1 errors in Compile ***
* Linking errors *
c:\fw6\samples>
Re: Creando Servicios con Harbour y xHarbour
Posted: Sat Sep 14, 2024 6:35 pm
by leandro
Antonio buenas tardes como estas, me compilo y ejecuto sin problema, pero no veo que haga nada
Code: Select all | Expand
┌────────────────────────────────────────────────────────────────────────────┐
?FiveWin for xHarbour 24.07 - Jul. 2024 Harbour development power │▄
?(c) FiveTech 1993-2024 for Microsoft Windows 9X/NT/200X/ME/XP/Vista/7/8/10 │█
└────────────────────────────────────────────────────────────────────────────┘?
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀?
Compiling...
xHarbour 1.3.1 Intl. (SimpLex) (Build 20240624)
Copyright 1999-2024, http://www.xharbour.org http://www.harbour-project.org/
Compiling 'servicio.prg' and generating preprocessed output to 'servicio.ppo'...
Generating C source output to 'servicio.c'...
Done.
Lines 9, Functions/Procedures 1, pCodes 15
Embarcadero C++ 7.70 for Win32 Copyright (c) 1993-2023 Embarcadero Technologies, Inc.
servicio.c:
Turbo Incremental Link 6.97 Copyright (c) 1997-2022 Embarcadero Technologies, Inc.
* Application successfully built *
C:\fwh2407\samples>
Re: Creando Servicios con Harbour y xHarbour
Posted: Sat Sep 14, 2024 8:02 pm
by alerchster
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
A continuación se ejecuta el servicio:
sc start servicio
Re: Creando Servicios con Harbour y xHarbour
Posted: Sat Sep 14, 2024 11:27 pm
by leandro
Re: Creando Servicios con Harbour y xHarbour
Posted: Sun Sep 15, 2024 5:05 am
by Antonio Linares
wilsongamboa wrote:Code: Select all | Expand
┌────────────────────────────────────────────────────────────────────────────┐
│ FiveWin for Harbour 24.07 - Jul. 2024 Harbour development power │▄
│ (c) FiveTech 1993-2024 for Microsoft Windows 9X/NT/200X/ME/XP/Vista/7/8/10 │█
└────────────────────────────────────────────────────────────────────────────┘█
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
Compiling...
Harbour 3.2.0dev (r2407221137)
Copyright (c) 1999-2021, https://harbour.github.io/
Compiling 'servicio.prg' and generating preprocessed output to 'servicio.ppo'..
Lines 5105, Functions/Procedures 1
Generating C source output to 'servicio.c'... Done.
Embarcadero C++ 7.70 for Win32 Copyright (c) 1993-2023 Embarcadero Technologies Inc.
servicio.c:
Warning W8065 servicio.prg 46: Call to function 'InitService' with no prototypein function ServiceMain
*** 1 errors in Compile ***
* Linking errors *
c:\fw6\samples>
Prueba a cambiar la línea 19 así:
int InitService( void );
debemos tener alguna diferencia en buildh.bat
Re: Creando Servicios con Harbour y xHarbour
Posted: Sun Sep 15, 2024 5:39 am
by Antonio Linares
Una vez hemos entendido la mecánica básica del servicio ahora voy a revisar el API creado por Jose Luis y probarlo con ambos Harbour y xHarbour
Re: Creando Servicios con Harbour y xHarbour
Posted: Sun Sep 15, 2024 6:13 am
by Antonio Linares
Probando el ejemplo c:\harbour\contrib\hbwin\tests\service.prg con
Harbour
Para construirlo:
Code: Select all | Expand
set path=c:\bcc77\bin
c:\harbour\bin\win\bcc\hbmk2 service.prg -comp=bcc -lhbwin
Abrimos ventana CMD como Administrador
Ejecutamos service.exe i
// OJO: parámetro i
Service has been successfully installed
Ejecutamos: service s ó simplemente service
Service has had some problems: 1063 El proceso del servicio no puede conectar con el controlador del servicio.
Ejecutamos: service u
Service has been deleted
Re: Creando Servicios con Harbour y xHarbour
Posted: Mon Sep 16, 2024 1:45 am
by RAMESHBABU
Dear Mr.Antonio,
I could build the EXE and the service is started.
Where I should insert the Business Logic in the
Loop?
Can you please give me a small example.
I tried like this to test
// Aquí va el bucle principal del servicio
while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
{
MemoWrit("MyTime.txt", Time());
// Realiza las tareas del servicio
Sleep(1000);
}
But it did not work.
-Ramesh Babu P
Re: Creando Servicios con Harbour y xHarbour
Posted: Mon Sep 16, 2024 2:50 am
by wilsongamboa
Master Antonio eso era gracias ya compilo OKs
Re: Creando Servicios con Harbour y xHarbour
Posted: Mon Sep 16, 2024 2:55 am
by wilsongamboa
Si logramos hacer eso vamos a tener muchas soluciones tengo _ para eso
saludos
Re: Creando Servicios con Harbour y xHarbour
Posted: Mon Sep 16, 2024 5:48 am
by Antonio Linares
Dear Ramesh,
servicio.prg
Code: Select all | Expand
// Once you build the EXE open a CMD window as Administrator, then:
// sc create servicio binPath=c:\fwh\samples\servicio.exe
// sc start servicio
// when you want to stop it: sc stop servicio
// when you want to remove it: sc delete servicio
// DON'T USE ANY GUI FROM IT !!!
#include "FiveWin.ch"
function Main()
Servicio()
return nil
function TrabajoServicio()
if ! File( "c:\fwh\samples\servicio.txt" )
memoWrit( "c:\fwh\samples\servicio.txt", Time() )
else
memoWrit( "c:\fwh\samples\servicio.txt", memoRead( "c:\fwh\samples\servicio.txt" ) + CRLF + Time() )
endif
return nil
#pragma BEGINDUMP
#include <windows.h>
#include <tchar.h>
#include <hbvm.h>
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService( void );
HB_FUNC( SERVICIO )
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = _T("Servicio");
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("Servicio"), (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
hb_vmPushSymbol( hb_dynsymSymbol( hb_dynsymFindName( "TRABAJOSERVICIO" ) ) );
hb_vmPushNil();
hb_vmDo( 0 );
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);
MessageBox( 0, "service stopped", "ok", 0 );
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