I have a service application created with Delphi, and managed to install it from another Delphi application using elevated privileges.
The service is set to log on as the Local System account (which is default when creating a service application in Delphi).
I have another Delphi application in which an ordinary user is supposed to be able to start or stop the above service.
My question is: Is this allowed by Windows? When I try to start the service using code in Delphi, it just fails with 'Code 5. Access is denied.' How can I prevent this error from occurring? I want to be able to have the normal user running the application (not in Administrator mode and thus not with elevated privileges) to start / stop the service. Is it possible and if so how? Below is my code:
function ServiceStart(sMachine, sService: string): boolean;
var
schm, schs: SC_Handle;
ss: TServiceStatus;
psTemp: PChar;
dwChkP: DWord; // check point
begin
ss.dwCurrentState := 0;
// connect to the service control manager
schm := OpenSCManager(PChar(sMachine), nil, SC_MANAGER_CONNECT);
// if successful...
if (schm <> 0) then
begin
// open a handle to the specified service
// we want to start the service and query service
// status
schs := OpenService(schm, PChar(sService), SERVICE_START or SERVICE_QUERY_STATUS);
// if successful...
if (schs <> 0) then
begin
psTemp := nil;
if (StartService(schs, 0, psTemp)) then
begin
// check status
if (QueryServiceStatus(schs, ss)) then
begin
while (SERVICE_RUNNING <> ss.dwCurrentState) do
begin
// dwCheckPoint contains a value that the
// service increments periodically to
// report its progress during a
// lengthy operation. Save current value
dwChkP := ss.dwCheckPoint;
// wait a bit before checking status again
// dwWaitHint is the estimated amount of
// time the calling program should wait
// before calling QueryServiceStatus()
// again. Idle events should be
// handled here...
Sleep(ss.dwWaitHint);
if not QueryServiceStatus(schs, ss) then
begin
// couldn't check status break from the
// loop
break;
end;
if ss.dwCheckPoint < dwChkP then
begin
// QueryServiceStatus didn't increment
// dwCheckPoint as it should have.
// Avoid an infinite loop by breaking
break;
end;
end;
end;
end
else
begin
if MessageDlg('Start Service failed. Do you want remove it?',
mtWarning, [mbYes, mbNo], 0) = mrYes then
begin
InstallUninstallService(1);
end;
end;
// close service handle
CloseServiceHandle(schs);
end else RaiseLastOSError;
// close service control manager handle
CloseServiceHandle(schm);
end;
// Return TRUE if the service status is running
Result := SERVICE_RUNNING = ss.dwCurrentState;
end;