Show message when running program as a service
- Jeff Barnes
- Posts: 912
- Joined: Sun Oct 09, 2005 1:05 pm
- Location: Ontario, Canada
- Contact:
Show message when running program as a service
How can you display a message to the user when a program is running as a service?
Thanks,
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
Re: Show message when running program as a service
Jeff:
How do you make a program run as a service ? Can you share the code ? Thank you very much !
How do you make a program run as a service ? Can you share the code ? Thank you very much !
- Jeff Barnes
- Posts: 912
- Joined: Sun Oct 09, 2005 1:05 pm
- Location: Ontario, Canada
- Contact:
Re: Show message when running program as a service
Thanks,
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
Re: Show message when running program as a service
Jeff:
Thank you very much !
Thank you very much !
- Jeff Barnes
- Posts: 912
- Joined: Sun Oct 09, 2005 1:05 pm
- Location: Ontario, Canada
- Contact:
Re: Show message when running program as a service
You are welcome...
I use 4 batch files.
InstallService.bat - called from my installer program
StartService.bat - called form my program when exiting the user interface
StopService.bat - called from my program when opening the user interface
UninstallService.bat - used if I need to remove the service
InstallService.bat
StartService.bat
StopService.bat
UninstallService.bat
I use 4 batch files.
InstallService.bat - called from my installer program
StartService.bat - called form my program when exiting the user interface
StopService.bat - called from my program when opening the user interface
UninstallService.bat - used if I need to remove the service
InstallService.bat
Code: Select all
c:\YourAppFolder\RunAsService install YourServiceName "Description of Your Service" C:\YourAppFolder\YouApp.exe
net start "YourServiceName"
StartService.bat
Code: Select all
net start "YourServiceName"
StopService.bat
Code: Select all
net stop "YourServiceName"
UninstallService.bat
Code: Select all
net stop "YourServiceName"
c:\YourAppFolder\RunAsService uninstall "YourServiceName"
Thanks,
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
- Antonio Linares
- Site Admin
- Posts: 37481
- Joined: Thu Oct 06, 2005 5:47 pm
- Location: Spain
- Contact:
Re: Show message when running program as a service
Jeff,
Please try this:
MsgInfo( GetModuleFileName( GetInstance() ) )
and see if there is a difference running as an EXE or as a service
Please try this:
MsgInfo( GetModuleFileName( GetInstance() ) )
and see if there is a difference running as an EXE or as a service
- Jeff Barnes
- Posts: 912
- Joined: Sun Oct 09, 2005 1:05 pm
- Location: Ontario, Canada
- Contact:
Re: Show message when running program as a service
Hi Antonio,
When I run the program normally (ie: user interface) I see the name of the exe.
When I close the program and Start the Service I do not see any messages at all.
When I run the program normally (ie: user interface) I see the name of the exe.
When I close the program and Start the Service I do not see any messages at all.
Thanks,
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
Re: Show message when running program as a service
Services with Harbour
Testsvc.prg
win_svc.c
Testsvc.prg
Code: Select all
/*
* $Id: testsvc.prg 18716 2012-12-03 13:52:22Z vszakats $
*/
/*
* Harbour Project source code:
* Windows Service API test code
*
* Copyright 2010 Jose Luis Capel - <jlcapel at hotmail . com>
* www - http://harbour-project.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING.txt. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
#if ! defined( __HBSCRIPT__HBSHELL )
#define _SERVICE_NAME "RisFilSrv"
PROCEDURE Main( cMode )
LOCAL nError
LOCAL cMsg
hb_default( @cMode, "S" ) /* NOTE: Must be the default action */
SWITCH Upper( cMode )
CASE "I"
IF win_serviceInstall( _SERVICE_NAME, "Harbour Windows Test Service" )
? "Service has been successfully installed"
ELSE
nError := wapi_GetLastError()
cMsg := Space( 128 )
wapi_FormatMessage( ,,,, @cMsg )
? "Error installing service: " + hb_ntos( nError ) + " " + cMsg
ENDIF
EXIT
CASE "U"
IF win_serviceDelete( _SERVICE_NAME )
? "Service has been deleted"
ELSE
nError := wapi_GetLastError()
cMsg := Space( 128 )
wapi_FormatMessage( ,,,, @cMsg )
? "Error deleting service: " + hb_ntos( nError ) + " " + cMsg
ENDIF
EXIT
CASE "S"
/* NOTE: Used when starting up as service.
Do not invoke the executable manually with this option */
IF win_serviceStart( _SERVICE_NAME, @SrvMain() )
? "Service has started OK"
ELSE
nError := wapi_GetLastError()
cMsg := Space( 128 )
wapi_FormatMessage( ,,,, @cMsg )
? "Service has had some problems: " + hb_ntos( nError ) + " " + cMsg
ENDIF
EXIT
CASE "START"
IF win_serviceInitiate( _SERVICE_NAME )
? "Service has started OK"
ELSE
nError := wapi_GetLastError()
cMsg := Space( 128 )
wapi_FormatMessage( ,,,, @cMsg )
? "Service has had some problems: " + hb_ntos( nError ) + " " + cMsg
ENDIF
EXIT
CASE "STOP"
IF win_serviceStoped( _SERVICE_NAME )
? "Service has stoped OK"
ELSE
nError := wapi_GetLastError()
cMsg := Space( 128 )
wapi_FormatMessage( ,,,, @cMsg )
? "Service has had some problems: " + hb_ntos( nError ) + " " + cMsg
ENDIF
EXIT
ENDSWITCH
RETURN
#include "fileio.ch"
PROCEDURE SrvMain( cParam1, cParam2 )
LOCAL n := 0
LOCAL fhnd := hb_FCreate( hb_DirBase() + "testsvc.out", FC_NORMAL, FO_DENYNONE + FO_WRITE )
LOCAL cParam
hb_default( @cParam1, "" )
hb_default( @cParam2, "" )
FWrite( fhnd, "Startup" + hb_eol() )
FWrite( fhnd, "|" + hb_CmdLine() + "|" + hb_eol() )
FWrite( fhnd, "|" + cParam1 + "|" + cParam2 + "|" + hb_eol() )
FOR EACH cParam IN hb_AParams()
FWrite( fhnd, "Parameter " + hb_ntos( cParam:__enumIndex() ) + " >" + cParam + "<" + hb_eol() )
NEXT
DO WHILE win_serviceGetStatus() == WIN_SERVICE_RUNNING
FWrite( fhnd, "Work in progress " + hb_ntos( ++n ) + hb_eol() )
hb_idleSleep( 0.5 )
ENDDO
FWrite( fhnd, "Exiting..." + hb_eol() )
FClose( fhnd )
win_serviceSetExitCode( 0 )
win_serviceStop()
RETURN
#else
PROCEDURE Main()
? "Cannot be used in script mode."
RETURN
#endif
Code: Select all
/*
* $Id: win_svc.c 18716 2012-12-03 13:52:22Z vszakats $
*/
/*
* Harbour Project source code:
* Windows Service API
*
* Copyright 2010 Jose Luis Capel - <jlcapel at hotmail . com>
* www - http://harbour-project.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING.txt. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
#include "hbwapi.h"
#include "hbapiitm.h"
#include "hbvm.h"
#include "hbstack.h"
#if ! defined( HB_OS_WIN_CE )
#if defined( __POCC__ ) || defined( __XCC__ )
# include <winsvc.h> /* it's disabled by WIN32_LEAN_AND_MEAN */
#endif
static SERVICE_STATUS s_ServiceStatus;
static SERVICE_STATUS_HANDLE s_hStatus;
static PHB_ITEM s_pHarbourEntryFunc = NULL;
static TCHAR s_lpServiceName[ 256 ];
/* Control handler function */
static VOID WINAPI hbwin_SvcControlHandler( DWORD fdwControl )
{
switch( fdwControl )
{
case SERVICE_CONTROL_STOP:
s_ServiceStatus.dwWin32ExitCode = 0;
s_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
return;
case SERVICE_CONTROL_SHUTDOWN:
s_ServiceStatus.dwWin32ExitCode = 0;
s_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
return;
}
SetServiceStatus( s_hStatus, &s_ServiceStatus ); /* Report current status */
}
static VOID WINAPI hbwin_SvcMainFunction( DWORD dwArgc, LPTSTR * lpszArgv )
{
s_ServiceStatus.dwServiceType = SERVICE_WIN32;
s_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
s_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
s_ServiceStatus.dwWin32ExitCode = 0;
s_ServiceStatus.dwServiceSpecificExitCode = 0;
s_ServiceStatus.dwCheckPoint = 0;
s_ServiceStatus.dwWaitHint = 0;
s_hStatus = RegisterServiceCtrlHandler( s_lpServiceName, ( LPHANDLER_FUNCTION ) hbwin_SvcControlHandler );
if( s_hStatus != ( SERVICE_STATUS_HANDLE ) 0 )
{
if( s_pHarbourEntryFunc != NULL )
{
if( hb_vmRequestReenterExt() )
{
DWORD i;
int iArgCount = 0;
/* We report the running status to SCM. */
s_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus( s_hStatus, &s_ServiceStatus );
hb_vmPushEvalSym();
hb_vmPush( s_pHarbourEntryFunc );
for( i = 1; i < dwArgc; ++i )
{
PHB_ITEM pItem = hb_stackAllocItem();
HB_ITEMPUTSTR( pItem, lpszArgv[ i ] );
if( hb_cmdargIsInternal( hb_itemGetCPtr( pItem ), NULL ) )
hb_stackPop();
else
++iArgCount;
}
hb_vmSend( ( HB_USHORT ) iArgCount );
hb_vmRequestRestore();
}
else
HB_TRACE( HB_TR_DEBUG, ( "HVM stack not available" ) );
}
else
HB_TRACE( HB_TR_DEBUG, ( "Harbour service entry function not found" ) );
}
else
HB_TRACE( HB_TR_DEBUG, ( "Error registering service" ) );
}
#endif
HB_FUNC( WIN_SERVICEGETSTATUS )
{
#if ! defined( HB_OS_WIN_CE )
hb_retnl( s_ServiceStatus.dwCurrentState );
#else
hb_retnl( 0 );
#endif
}
HB_FUNC( WIN_SERVICESETSTATUS )
{
#if ! defined( HB_OS_WIN_CE )
s_ServiceStatus.dwCurrentState = ( DWORD ) hb_parnl( 1 );
hb_retl( SetServiceStatus( s_hStatus, &s_ServiceStatus ) );
#else
hb_retl( HB_FALSE );
#endif
}
HB_FUNC( WIN_SERVICESETEXITCODE )
{
#if ! defined( HB_OS_WIN_CE )
s_ServiceStatus.dwWin32ExitCode = ( DWORD ) hb_parnl( 1 );
hb_retl( SetServiceStatus( s_hStatus, &s_ServiceStatus ) );
#else
hb_retl( HB_FALSE );
#endif
}
HB_FUNC( WIN_SERVICESTOP )
{
#if ! defined( HB_OS_WIN_CE )
s_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus( s_hStatus, &s_ServiceStatus );
#endif
}
HB_FUNC( WIN_SERVICEINSTALL )
{
HB_BOOL bRetVal = HB_FALSE;
#if ! defined( HB_OS_WIN_CE )
void * hPath;
LPCTSTR lpPath = HB_PARSTR( 3, &hPath, NULL );
TCHAR lpPathBuffer[ MAX_PATH ];
if( lpPath == NULL )
{
if( GetModuleFileName( NULL, lpPathBuffer, HB_SIZEOFARRAY( lpPathBuffer ) ) )
lpPath = lpPathBuffer;
else
hbwapi_SetLastError( GetLastError() );
}
if( lpPath )
{
SC_HANDLE schSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if( schSCM )
{
SC_HANDLE schSrv;
void * hServiceName;
void * hDisplayName;
LPCTSTR lpServiceName = HB_PARSTRDEF( 1, &hServiceName, NULL );
LPCTSTR lpDisplayName = HB_PARSTRDEF( 2, &hDisplayName, NULL );
schSrv = CreateService( schSCM, /* SCM database */
lpServiceName, /* name of service */
lpDisplayName, /* service name to display */
SERVICE_ALL_ACCESS, /* desired access */
SERVICE_WIN32_OWN_PROCESS, /* service type */
HB_ISNUM( 4 ) ? ( DWORD ) hb_parnl( 4 ) : SERVICE_DEMAND_START,
/* start type */
SERVICE_ERROR_NORMAL, /* error control type */
lpPath, /* path to service's binary */
NULL, /* no load ordering group */
NULL, /* no tag identifier */
NULL, /* no dependencies */
NULL, /* LocalSystem account */
NULL ); /* no password */
if( schSrv )
{
bRetVal = HB_TRUE;
CloseServiceHandle( schSrv );
}
else
hbwapi_SetLastError( GetLastError() );
hb_strfree( hServiceName );
hb_strfree( hDisplayName );
CloseServiceHandle( schSCM );
}
else
hbwapi_SetLastError( GetLastError() );
}
hb_strfree( hPath );
#endif
hb_retl( bRetVal );
}
HB_FUNC( WIN_SERVICEDELETE )
{
HB_BOOL bRetVal = HB_FALSE;
#if ! defined( HB_OS_WIN_CE )
SC_HANDLE schSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if( schSCM )
{
void * hServiceName;
SC_HANDLE schSrv = OpenService( schSCM,
HB_PARSTRDEF( 1, &hServiceName, NULL ),
SERVICE_ALL_ACCESS );
if( schSrv )
{
/* TODO: check if service is up and then stop it */
bRetVal = ( HB_BOOL ) DeleteService( schSrv );
CloseServiceHandle( schSrv );
}
else
hbwapi_SetLastError( GetLastError() );
hb_strfree( hServiceName );
CloseServiceHandle( schSCM );
}
else
hbwapi_SetLastError( GetLastError() );
#endif
hb_retl( bRetVal );
}
HB_FUNC( WIN_SERVICESTART )
{
HB_BOOL bRetVal = HB_FALSE;
#if ! defined( HB_OS_WIN_CE )
PHB_ITEM pEntryFunc;
SERVICE_TABLE_ENTRY lpServiceTable[ 2 ];
HB_ITEMCOPYSTR( hb_param( 1, HB_IT_STRING ), s_lpServiceName, HB_SIZEOFARRAY( s_lpServiceName ) );
if( s_pHarbourEntryFunc )
{
hb_itemRelease( s_pHarbourEntryFunc );
s_pHarbourEntryFunc = NULL;
}
pEntryFunc = hb_param( 2, HB_IT_BLOCK | HB_IT_SYMBOL );
if( pEntryFunc )
s_pHarbourEntryFunc = hb_itemNew( pEntryFunc );
lpServiceTable[ 0 ].lpServiceName = s_lpServiceName;
lpServiceTable[ 0 ].lpServiceProc = ( LPSERVICE_MAIN_FUNCTION ) hbwin_SvcMainFunction;
lpServiceTable[ 1 ].lpServiceName = NULL;
lpServiceTable[ 1 ].lpServiceProc = NULL;
if( StartServiceCtrlDispatcher( lpServiceTable ) )
bRetVal = HB_TRUE;
else
hbwapi_SetLastError( GetLastError() );
#endif
hb_retl( bRetVal );
}
HB_FUNC( WIN_SERVICEINITIATE )
{
HB_BOOL bRetVal = HB_FALSE;
#if ! defined( HB_OS_WIN_CE )
// open a handle to the SCM
SC_HANDLE schSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if( schSCM )
{
// open a handle to the service
void * hServiceName;
SC_HANDLE schSrv = OpenService( schSCM, HB_PARSTRDEF( 1, &hServiceName, NULL ), GENERIC_EXECUTE );
if( schSrv )
{
if( ! ( bRetVal = StartService( schSrv, 0, NULL ) ) )
hbwapi_SetLastError( GetLastError() );
}else
hbwapi_SetLastError( GetLastError() );
hb_strfree( hServiceName );
CloseServiceHandle( schSrv );
CloseServiceHandle( schSCM );
}else
hbwapi_SetLastError( GetLastError() );
#endif
hb_retl( bRetVal );
}
HB_FUNC( WIN_SERVICESTOPED )
{
HB_BOOL bRetVal = HB_FALSE;
#if ! defined( HB_OS_WIN_CE )
// open a handle to the SCM
SC_HANDLE schSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if( schSCM )
{
void * hServiceName;
// open a handle to the service
SC_HANDLE schSrv = OpenService( schSCM, HB_PARSTRDEF( 1, &hServiceName, NULL ), GENERIC_EXECUTE );
if( schSrv ){
// send the STOP control request to the service
SERVICE_STATUS status;
ControlService( schSrv, SERVICE_CONTROL_STOP, &status );
CloseServiceHandle( schSrv );
CloseServiceHandle( schSCM );
if( ( bRetVal = status.dwCurrentState != SERVICE_STOPPED ) )
hbwapi_SetLastError( GetLastError() );
hb_strfree( hServiceName );
}else
hbwapi_SetLastError( GetLastError() );
}else
hbwapi_SetLastError( GetLastError() );
#endif
hb_retl( bRetVal );
}
Manfred Groß
- Antonio Linares
- Site Admin
- Posts: 37481
- Joined: Thu Oct 06, 2005 5:47 pm
- Location: Spain
- Contact:
Re: Show message when running program as a service
Jeff,
Ok, thats because services are not allowed to show a MsgInfo()
Change it into a call to LogFile() or OutputDebugString()
Ok, thats because services are not allowed to show a MsgInfo()
Change it into a call to LogFile() or OutputDebugString()
Re: Show message when running program as a service
You can allow service to interact with the desktop.
See if the info below helps.
See if the info below helps.
Although typically services do not have a user interface, developers can add forms and other UI components. In this case, the "Allow service to interact with desktop" should be checked on the Logon tab in the Service properties dialog (though care should be taken with this approach as this can cause a security risk since any logged in user would be able to interact with the service)
- Jeff Barnes
- Posts: 912
- Joined: Sun Oct 09, 2005 1:05 pm
- Location: Ontario, Canada
- Contact:
Re: Show message when running program as a service
Tried OutputDebugString("TEST") ... nothing is displayed.
Verified that I have "allow service to interact with desktop" checked ... nothing is displayed.
I have come up with a work-around ... Since the service interacts with another running program I can use the Running Program to display the messages I need.
Thanks for all the input with this one
Verified that I have "allow service to interact with desktop" checked ... nothing is displayed.
I have come up with a work-around ... Since the service interacts with another running program I can use the Running Program to display the messages I need.
Thanks for all the input with this one
Thanks,
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
- Antonio Linares
- Site Admin
- Posts: 37481
- Joined: Thu Oct 06, 2005 5:47 pm
- Location: Spain
- Contact:
Re: Show message when running program as a service
Jeff,
https://bitbucket.org/fivetech/fivewin- ... bwin32.zip
Did you had dbwin32.exe running to see the output messages from OutputDebugString() ?Tried OutputDebugString("TEST") ... nothing is displayed
https://bitbucket.org/fivetech/fivewin- ... bwin32.zip
- Jeff Barnes
- Posts: 912
- Joined: Sun Oct 09, 2005 1:05 pm
- Location: Ontario, Canada
- Contact:
Re: Show message when running program as a service
Just tried with DBWIN32 running ... still nothing is displayed.
Thanks,
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
Jeff Barnes
(FWH 12.01, xHarbour 1.2.1, Bcc582)
Re: Show message when running program as a service
There is another way using Windows Interactive Service.
https://msdn.microsoft.com/en-us/librar ... 85%29.aspx
https://msdn.microsoft.com/en-us/librar ... 85%29.aspx
Re: Show message when running program as a service
Regarding output from OutputDebugString(): Unless you've explicitly configured the service to run under a specific account, the service will be running as System. The debug viewer running under your desktop account likely doesn't have sufficient privilege to see these messages. That is certainly my experience. I happen to use DebugView from sysinternals. For it to see OutputDebugString() messages Capture Global Win32 messages must be enabled, which in DebugView is disabled by default. To enable that requires that I launch DebugView as Administrator.
It shouldn't matter for the above paragraph but I also don't use any external helper for any of my services (let's me stay with only a single .exe for an app). I've used the service manager control example from the harbour hbwin contribution, it's pretty straightforward.
Robb
It shouldn't matter for the above paragraph but I also don't use any external helper for any of my services (let's me stay with only a single .exe for an app). I've used the service manager control example from the harbour hbwin contribution, it's pretty straightforward.
Robb