No, there isn't. You can only work with processes you spawn yourself via Command.
std isn't meant to be comprehensive. It's kept minimal on purpose. Expect almost everything in Rust to be done via 3rd party crates or interact directly with OS APIs.
For example, starting and stopping services with OS APIs would look like the C++ example at Starting a Service - Win32 apps | Microsoft Docs, but adapted for Rust. With some wrappers around handles for convenience, that can look like this:
use std::marker::PhantomData;
use std::mem::{size_of, MaybeUninit};
use std::thread::sleep;
use std::time::{Instant, Duration};
use windows::core::HSTRING;
use windows::w;
use windows::Win32::Security::SC_HANDLE;
use windows::Win32::System::Services::{CloseServiceHandle, OpenSCManagerW, SC_MANAGER_ALL_ACCESS, OpenServiceW, SERVICE_ALL_ACCESS, QueryServiceStatusEx, SC_STATUS_PROCESS_INFO, SERVICE_STATUS_PROCESS, SERVICE_STOPPED, SERVICE_STOP_PENDING, StartServiceW, SERVICE_START_PENDING, SERVICE_RUNNING};
fn main() {
do_start_service().unwrap();
}
struct SCManagerHandle(SC_HANDLE);
impl SCManagerHandle {
pub fn open() -> windows::core::Result<Self> {
let handle = unsafe {
OpenSCManagerW(None, None, SC_MANAGER_ALL_ACCESS)?
};
Ok(SCManagerHandle(handle))
}
pub fn open_service(&self, servicename: &HSTRING) -> windows::core::Result<ServiceHandle> {
let handle = unsafe {
OpenServiceW(self.0, servicename, SERVICE_ALL_ACCESS)?
};
Ok(ServiceHandle(handle, PhantomData))
}
}
impl Drop for SCManagerHandle {
fn drop(&mut self) {
unsafe { CloseServiceHandle(self.0); }
}
}
struct ServiceHandle<'a>(SC_HANDLE, PhantomData<&'a SCManagerHandle>);
impl ServiceHandle<'_> {
pub fn query_status(&self) -> windows::core::Result<SERVICE_STATUS_PROCESS> {
let mut bytes_needed = 0u32;
let mut status: MaybeUninit<SERVICE_STATUS_PROCESS> = MaybeUninit::uninit();
unsafe {
QueryServiceStatusEx(
self.0,
SC_STATUS_PROCESS_INFO,
status.as_mut_ptr().cast(),
size_of::<SERVICE_STATUS_PROCESS>() as u32,
&mut bytes_needed
).ok().map(|_| status.assume_init())
}
}
pub fn start(&self) -> windows::core::Result<()> {
unsafe {
StartServiceW(self.0, &[]).ok()
}
}
}
impl Drop for ServiceHandle<'_> {
fn drop(&mut self) {
unsafe { CloseServiceHandle(self.0); }
}
}
fn do_start_service() -> windows::core::Result<()> {
let sc_manager = SCManagerHandle::open()?;
let service = sc_manager.open_service(w!("ssh-agent"))?;
let mut status = service.query_status()?;
if status.dwCurrentState != SERVICE_STOPPED && status.dwCurrentState != SERVICE_STOP_PENDING {
eprintln!("Service is already running");
return Ok(());
}
let mut start_time = Instant::now();
let mut old_checkpoint = status.dwCheckPoint;
while status.dwCurrentState == SERVICE_STOP_PENDING {
let wait_time = (status.dwWaitHint / 10).clamp(1000, 10000);
sleep(Duration::from_millis(wait_time.into()));
status = service.query_status()?;
if status.dwCheckPoint > old_checkpoint {
start_time = Instant::now();
old_checkpoint = status.dwCheckPoint;
} else if Instant::now().duration_since(start_time) > Duration::from_millis(status.dwWaitHint.into()) {
eprintln!("Timeout waiting for service to stop.");
return Ok(());
}
}
service.start()?;
println!("Service start pending...");
status = service.query_status()?;
start_time = Instant::now();
old_checkpoint = status.dwCheckPoint;
while status.dwCurrentState == SERVICE_START_PENDING {
let wait_time = (status.dwWaitHint / 10).clamp(1000, 10000);
sleep(Duration::from_millis(wait_time.into()));
status = service.query_status()?;
if status.dwCheckPoint > old_checkpoint {
start_time = Instant::now();
old_checkpoint = status.dwCheckPoint;
} else if Instant::now().duration_since(start_time) > Duration::from_millis(status.dwWaitHint.into()) {
break;
}
}
if status.dwCurrentState == SERVICE_RUNNING {
println!("Service started successfully.");
} else {
eprintln!("Service not started.");
eprintln!(" Current state: {:?}", status.dwCurrentState);
eprintln!(" Exit code: {:08X}", status.dwWin32ExitCode);
eprintln!(" Check point: {}", status.dwCheckPoint);
eprintln!(" Wait hint: {}", status.dwWaitHint);
}
Ok(())
}