Еще вариант, суть таже, но с проверками всякими, остановом зависимых сервисов и ожиданием старта и останова. Код мсдн-ский: http://msdn2.microsoft.com/en-us/library/ms686315.aspx http://msdn2.microsoft.com/en-us/library/ms686335.aspx переписал на Delphi:
| Код | PServiceStatusProcess = ^TServiceStatusProcess; {$EXTERNALSYM _SERVICE_STATUS_PROCESS} _SERVICE_STATUS_PROCESS = record dwServiceType: DWORD; dwCurrentState: DWORD; dwControlsAccepted: DWORD; dwWin32ExitCode: DWORD; dwServiceSpecificExitCode: DWORD; dwCheckPoint: DWORD; dwWaitHint: DWORD; dwProcessId: DWORD; dwServiceFlags: DWORD; end; {$EXTERNALSYM SERVICE_STATUS_PROCESS} SERVICE_STATUS_PROCESS = _SERVICE_STATUS_PROCESS; TServiceStatusProcess = _SERVICE_STATUS_PROCESS;
const SC_STATUS_PROCESS_INFO = 0; HEAP_ZERO_MEMORY = $00000008;
function QueryServiceStatusEx(hService: DWORD; InfoLevel: DWORD; var lpServiceStatus: SERVICE_STATUS_PROCESS; cbBufSize: DWORD; pcbBytesNeeded: LPDWORD): BOOL; stdcall; external advapi32;
function StopCustomService(hSCM: DWord; hService: DWORD; StopDependencies: BOOL; dwTimeout: DWORD): DWORD; var i: Integer;
ssp: SERVICE_STATUS_PROCESS; ss: SERVICE_STATUS; ess: _ENUM_SERVICE_STATUS;
dwStartTime, dwBytesNeeded: DWORD; dwCount: DWORD; lpDependencies: PEnumServiceStatus; hDepService: DWORD; begin dwStartTime := GetTickCount;
// Make sure the service is not already stopped if not QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, ssp, SizeOf(SERVICE_STATUS_PROCESS), @dwTimeout) then begin Result := GetLastError; Exit; end;
if ssp.dwCurrentState = SERVICE_STOPPED then Result := ERROR_SUCCESS;
// If a stop is pending, just wait for it while ssp.dwCurrentState = SERVICE_STOP_PENDING do begin Sleep(ssp.dwWaitHint); if not QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, ssp, SizeOf(SERVICE_STATUS_PROCESS), @dwTimeout) then Result := GetLastError;
if ssp.dwCurrentState = SERVICE_STOPPED then Result := ERROR_SUCCESS;
if GetTickCount - dwStartTime > dwTimeout then Result := ERROR_TIMEOUT; end;
// If the service is running, dependencies must be stopped first if StopDependencies then begin // Pass a zero-length buffer to get the required buffer size if not EnumDependentServices(hService, SERVICE_ACTIVE, lpDependencies^, 0, dwBytesNeeded, dwCount) then // If the Enum call succeeds, then there are no dependent // services so do nothing begin if GetLastError <> ERROR_MORE_DATA then Result := GetLastError; // Unexpected error
// Allocate a buffer for the dependencies lpDependencies := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwBytesNeeded); if Assigned(lpDependencies) then begin try // Enumerate the dependencies if not EnumDependentServices(hService, SERVICE_ACTIVE, lpDependencies^, dwBytesNeeded, dwBytesNeeded, dwCount) then Result := GetLastError();
for i := 0 to dwCount - 1 do begin lpDependencies := Pointer(Integer(lpDependencies) + i); MoveMemory(@ess, lpDependencies, SizeOf(_ENUM_SERVICE_STATUS));
// Open the service hDepService := OpenService(hSCM, ess.lpServiceName, SERVICE_STOP or SERVICE_QUERY_STATUS);
if hDepService = 0 then Result := GetLastError;
try // Send a stop code if not ControlService(hDepService, SERVICE_CONTROL_STOP, ss) then Result := GetLastError;
// Wait for the service to stop while ss.dwCurrentState <> SERVICE_STOPPED do begin Sleep(ssp.dwWaitHint); if not QueryServiceStatusEx(hDepService, SC_STATUS_PROCESS_INFO, ssp, SizeOf(SERVICE_STATUS_PROCESS), @dwBytesNeeded) then Result := GetLastError;
if (ssp.dwCurrentState = SERVICE_STOPPED ) then Break;
if (GetTickCount() - dwStartTime > dwTimeout ) then Result := ERROR_TIMEOUT; end; finally // Always release the service handle CloseServiceHandle( hDepService ); end;
end;
finally // Always free the enumeration buffer HeapFree( GetProcessHeap, 0, lpDependencies); end;
end else Result := GetLastError; end;
end;
// Send a stop code to the main service if not ControlService(hService, SERVICE_CONTROL_STOP, ss) then Result := GetLastError;
// Wait for the service to stop while ss.dwCurrentState <> SERVICE_STOPPED do begin Sleep(ss.dwWaitHint ); if not QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, ssp, sizeof(SERVICE_STATUS_PROCESS), @dwBytesNeeded) then Result := GetLastError;
if (ssp.dwCurrentState = SERVICE_STOPPED ) then Break;
if GetTickCount() - dwStartTime > dwTimeout then Result := ERROR_TIMEOUT;
end; // Return success Result := ERROR_SUCCESS; end;
function StartCustomService(hService: DWORD; dwTimeout: DWORD): DWORD; var ssStatus: SERVICE_STATUS_PROCESS; dwOldCheckPoint: DWORD; dwStartTickCount: DWORD; dwWaitTime: DWORD; dwBytesNeeded: DWORD; pTmp: PChar; begin pTmp := nil;
if not StartService(hService, 0, pTmp) then begin Result := GetLastError; Exit; end;
// Check the status until the service is no longer start pending.
if not QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, ssStatus, SizeOf(SERVICE_STATUS_PROCESS), @dwBytesNeeded) then begin Result := GetLastError; Exit; end;
// Save the tick count and initial checkpoint.
dwStartTickCount := GetTickCount; dwOldCheckPoint := ssStatus.dwCheckPoint;
while ssStatus.dwCurrentState = SERVICE_START_PENDING do begin dwWaitTime := Round(ssStatus.dwWaitHint / 10); if dwWaitTime < 1000 then dwWaitTime := 1000 else if dwWaitTime > 10000 then dwWaitTime := 10000;
Sleep(dwWaitTime);
// Check the status again.
if not QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, ssStatus, SizeOf(SERVICE_STATUS_PROCESS), @dwBytesNeeded) then Break;
if ssStatus.dwCheckPoint > dwOldCheckPoint then begin // The service is making progress. dwStartTickCount := GetTickCount; dwOldCheckPoint := ssStatus.dwCheckPoint; end else if GetTickCount - dwStartTickCount > dwTimeout then begin // No progress made within the wait hint Result := ERROR_TIMEOUT; Break; end; end;
Result := ERROR_SUCCESS; end;
|
Использовать:
| Код | var hService, hSCManager: DWORD; lMachineName: string; begin lMachineName := GetEnvironmentVariable('COMPUTERNAME'); hSCManager := OpenSCManager(PChar(lMachineName), SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); if hSCManager > 0 then begin hService := OpenService(hSCManager, 'FwcAgent', SC_MANAGER_ALL_ACCESS); if hService > 0 then begin if (StopCustomService(hSCManager, hService, False, 10000) <> 0) or (StartCustomService(hService, 10000) <> 0) then RaiseLastOSError; CloseServiceHandle(hService); end else RaiseLastOSError; CloseServiceHandle(hSCManager); end else RaiseLastOSError;
|
|