/// <summary> /// Get the Win32 services for the SCM. /// </summary> /// <param name="service_state">The state of the services to return.</param> /// <param name="service_types">The types of services to return.</param> /// <param name="throw_on_error">True throw on error.</param> /// <returns>The list of services.</returns> /// <remarks>SCM must have been opened with EnumerateService access.</remarks> public NtResult <IEnumerable <Win32Service> > GetServices(ServiceState service_state, ServiceType service_types, bool throw_on_error) { SERVICE_STATE state; switch (service_state) { case ServiceState.All: state = SERVICE_STATE.SERVICE_STATE_ALL; break; case ServiceState.Active: state = SERVICE_STATE.SERVICE_ACTIVE; break; case ServiceState.InActive: state = SERVICE_STATE.SERVICE_INACTIVE; break; default: throw new ArgumentException("Invalid service state", nameof(service_state)); } List <Win32Service> ret_services = new List <Win32Service>(); const int Length = 32 * 1024; using (var buffer = new SafeHGlobalBuffer(Length)) { int resume_handle = 0; while (true) { bool ret = Win32NativeMethods.EnumServicesStatusEx(_handle, SC_ENUM_TYPE.SC_ENUM_PROCESS_INFO, service_types, state, buffer, buffer.Length, out int bytes_needed, out int services_returned, ref resume_handle, null); Win32Error error = Win32Utils.GetLastWin32Error(); if (!ret && error != Win32Error.ERROR_MORE_DATA) { return(error.CreateResultFromDosError <IEnumerable <Win32Service> >(throw_on_error)); } ENUM_SERVICE_STATUS_PROCESS[] services = new ENUM_SERVICE_STATUS_PROCESS[services_returned]; buffer.ReadArray(0, services, 0, services_returned); ret_services.AddRange(services.Select(s => new Win32Service(_machine_name, s))); if (ret) { break; } } } return(ret_services.CreateResult().Cast <IEnumerable <Win32Service> >()); }