On 2006-08-15 20:21, Alexandre Leclerc wrote:
Thank you for all this information Boguslaw. I'll have a look into
that. The moment it works, I don't care about usual warpers.
I created this little example some time ago. It will also show you how
to install/uninstall the service under win32.
Take care
Søren
program Service;
{$mode objfpc}{$H+}
uses
Classes, Windows, SysUtils;
VAR
MyServiceStatus : SERVICE_STATUS;
MyServiceStatusHandle : SERVICE_STATUS_HANDLE;
PROCEDURE SvcDebugOut(Msg: String; Status: Dword);
VAR
Buffer: ARRAY[0..1024] OF Char;
BEGIN
IF Length(Msg) < 1000 THEN
BEGIN
Buffer:=Format(Msg, [Status]);
OutputDebugStringA(Buffer);
END;
END;
FUNCTION MyServiceCtrlHandler(Opcode: DWord): LongBool; StdCall;
VAR
status: DWord;
BEGIN
case Opcode of
SERVICE_CONTROL_PAUSE:
BEGIN
// Do whatever it takes to pause here.
MyServiceStatus.dwCurrentState := SERVICE_PAUSED;
END;
SERVICE_CONTROL_CONTINUE:
BEGIN
// Do whatever it takes to continue here.
MyServiceStatus.dwCurrentState := SERVICE_RUNNING;
END;
SERVICE_CONTROL_STOP:
BEGIN
// Do whatever it takes to stop here.
MyServiceStatus.dwWin32ExitCode := 0;
MyServiceStatus.dwCurrentState := SERVICE_STOPPED;
MyServiceStatus.dwCheckPoint := 0;
MyServiceStatus.dwWaitHint := 0;
IF NOT SetServiceStatus(MyServiceStatusHandle, @MyServiceStatus) THEN
SvcDebugOut(' [SERVICE] SetServiceStatus error %ld\n', GetLastError());
SvcDebugOut(' [SERVICE] Leaving MyService \n',0);
exit;
END;
SERVICE_CONTROL_INTERROGATE: ;
// Fall through to send current status.
else
SvcDebugOut(' [SERVICE] Unrecognized opcode %ld\n', Opcode);
end;
// Send current status.
IF NOT SetServiceStatus (MyServiceStatusHandle, @MyServiceStatus) THEN
SvcDebugOut(' [MY_SERVICE] SetServiceStatus error %ld\n', GetLastError());
END;
// Stub initialization function.
FUNCTION MyServiceInitialization(argc: DWord; argv: LPTSTR; VAR specificError:
DWord): DWord;
BEGIN
MyServiceInitialization:=0;
END;
PROCEDURE MyServiceStart(argc: DWORD; argv: LPTSTR); StdCall;
VAR
status: DWord;
specificError: DWord;
BEGIN
MyServiceStatus.dwServiceType := SERVICE_WIN32;
MyServiceStatus.dwCurrentState := SERVICE_START_PENDING;
MyServiceStatus.dwControlsAccepted := SERVICE_ACCEPT_STOP OR
SERVICE_ACCEPT_PAUSE_CONTINUE;
MyServiceStatus.dwWin32ExitCode := 0;
MyServiceStatus.dwServiceSpecificExitCode := 0;
MyServiceStatus.dwCheckPoint := 0;
MyServiceStatus.dwWaitHint := 0;
MyServiceStatusHandle := RegisterServiceCtrlHandler('Service',
@MyServiceCtrlHandler);
IF (MyServiceStatusHandle = 0) THEN
BEGIN
SvcDebugOut(' [SERVICE] RegisterServiceCtrlHandler failed %d\n',
GetLastError());
exit;
END;
// Initialization code goes here.
status := MyServiceInitialization(argc,argv,specificError);
// Handle error condition
IF status <> NO_ERROR THEN
BEGIN
MyServiceStatus.dwCurrentState := SERVICE_STOPPED;
MyServiceStatus.dwCheckPoint := 0;
MyServiceStatus.dwWaitHint := 0;
MyServiceStatus.dwWin32ExitCode := status;
MyServiceStatus.dwServiceSpecificExitCode := specificError;
SetServiceStatus(MyServiceStatusHandle, @MyServiceStatus);
exit;
END;
// Initialization complete - report running status.
MyServiceStatus.dwCurrentState := SERVICE_RUNNING;
MyServiceStatus.dwCheckPoint := 0;
MyServiceStatus.dwWaitHint := 0;
IF NOT SetServiceStatus(MyServiceStatusHandle, @MyServiceStatus) THEN
BEGIN
status := GetLastError();
SvcDebugOut(' [SERVICE] SetServiceStatus error %ld\n',status);
END;
// This is where the service does its work.
while MyServiceStatus.dwCurrentState <> SERVICE_STOPPED do
begin
Sleep(2);
end;
SvcDebugOut(' [SERVICE] Returning the Main Thread \n',0);
END;
FUNCTION CreateSampleService: Boolean;
VAR
szPath: ARRAY[0..MAX_PATH] OF Char;
schSCManager: SC_HANDLE;
schService: SC_HANDLE;
BEGIN
IF GetModuleFileName(0, szPath, MAX_PATH)=0 THEN
BEGIN
WriteLn(Format('GetModuleFileName failed (%d)', [GetLastError()]));
Result:=False;
Exit;
END;
schSCManager := OpenSCManager(
nil, // local machine
nil, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
IF schSCManager=0 THEN
BEGIN
WriteLn(Format('OpenSCManager failed (%d)', [GetLastError()]));
Result:=False;
Exit;
END;
schService := CreateService(
schSCManager, // SCManager database
'Service', // name of service
'My test service', // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_DEMAND_START, // start type
SERVICE_ERROR_NORMAL, // error control type
szPath, // path to service's binary
nil, // no load ordering group
nil, // no tag identifier
nil, // no dependencies
nil, // LocalSystem account
nil); // no password
IF schService=0 THEN
BEGIN
CloseServiceHandle(schSCManager);
WriteLn(Format('CreateService failed (%d)', [GetLastError()]));
Result:=False;
END ELSE
BEGIN
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
WriteLn('CreateService sucessfull');
Result:=True;
END;
END;
FUNCTION DeleteSampleService: Boolean;
VAR
schSCManager: SC_HANDLE;
schService: SC_HANDLE;
BEGIN
schSCManager := OpenSCManager(
nil, // local machine
nil, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
IF schSCManager=0 THEN
BEGIN
WriteLn(Format('OpenSCManager failed (%d)', [GetLastError()]));
Result:=False;
Exit;
END;
schService := OpenService(
schSCManager, // SCManager database
'Service', // name of service
SERVICE_DELETE); // only need DELETE access
IF schService=0 THEN
BEGIN
CloseServiceHandle(schSCManager);
WriteLn(Format('OpenService failed (%d)', [GetLastError()]));
Result:=False;
END;
IF NOT DeleteService(schService) THEN
BEGIN
WriteLn(Format('DeleteService failed (%d)', [GetLastError()]));
Result:=False;
END ELSE
BEGIN
WriteLn('DeleteService succeeded');
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
Result:=False;
END;
END;
VAR
DispatchTable: ARRAY[1..2] OF SERVICE_TABLE_ENTRY;
BEGIN
// TODO: Better parm handeling
IF ParamStr(1)='install' THEN
CreateSampleService
ELSE
IF ParamStr(1)='uninstall' THEN
DeleteSampleService
ELSE
BEGIN
FillChar(DispatchTable, SizeOf(DispatchTable), 0);
DispatchTable[1].lpServiceName:='Service';
DispatchTable[1].lpServiceProc:[EMAIL PROTECTED];
IF NOT StartServiceCtrlDispatcher(@DispatchTable) THEN
SvcDebugOut(' [SERVICE] StartServiceCtrlDispatcher
(%d)\n',GetLastError());
END;
END.