#![allow(clippy::missing_errors_doc)]
use windows::core::HSTRING;
use windows::Win32::System::HostComputeSystem::{
HcsCreateProcess, HcsGetProcessProperties, HcsModifyProcess, HcsOpenProcess, HcsSignalProcess,
HcsTerminateProcess, HCS_PROCESS, HCS_SYSTEM,
};
use crate::error::{HcsError, HcsResult};
use crate::handle::{OwnedProcess, SendHandle};
use crate::operation::run_operation;
use crate::schema::ProcessParameters;
#[derive(Debug)]
pub struct ComputeProcess {
inner: OwnedProcess,
}
impl ComputeProcess {
pub async fn create(
system: SendHandle<HCS_SYSTEM>,
process_parameters_json: &str,
) -> HcsResult<Self> {
let params_w = HSTRING::from(process_parameters_json);
let mut created: Option<SendHandle<HCS_PROCESS>> = None;
let created_slot = &mut created;
let _ = run_operation(|op| {
match unsafe { HcsCreateProcess(*system, ¶ms_w, op, None) } {
Ok(handle) => {
*created_slot = Some(SendHandle(handle));
windows::core::HRESULT(0)
}
Err(e) => e.code(),
}
})
.await?;
let raw = created.ok_or_else(|| HcsError::Other {
hresult: 0,
message: "HcsCreateProcess succeeded but produced no handle".to_string(),
})?;
if raw.0.is_invalid() {
return Err(HcsError::Other {
hresult: 0,
message: "HcsCreateProcess returned invalid handle".to_string(),
});
}
Ok(Self {
inner: unsafe { OwnedProcess::from_raw(raw.0) },
})
}
pub async fn spawn(
system: SendHandle<HCS_SYSTEM>,
params: &ProcessParameters,
) -> HcsResult<Self> {
let json = serde_json::to_string(params)?;
Self::create(system, &json).await
}
pub fn open(system: HCS_SYSTEM, process_id: u32, requested_access: u32) -> HcsResult<Self> {
let raw = unsafe { HcsOpenProcess(system, process_id, requested_access) }.map_err(|e| {
HcsError::from_hresult(e.code(), format!("HcsOpenProcess(pid={process_id})"))
})?;
if raw.is_invalid() {
return Err(HcsError::Other {
hresult: 0,
message: "HcsOpenProcess returned invalid handle".to_string(),
});
}
Ok(Self {
inner: unsafe { OwnedProcess::from_raw(raw) },
})
}
#[must_use]
pub fn raw(&self) -> SendHandle<HCS_PROCESS> {
self.inner.as_raw()
}
pub async fn signal(&self, options_json: &str) -> HcsResult<()> {
let opts_w = HSTRING::from(options_json);
let handle = self.inner.as_raw();
run_operation(move |op| {
match unsafe { HcsSignalProcess(*handle, op, &opts_w) } {
Ok(()) => windows::core::HRESULT(0),
Err(e) => e.code(),
}
})
.await?;
Ok(())
}
pub async fn terminate(&self, options_json: &str) -> HcsResult<()> {
let opts_w = HSTRING::from(options_json);
let handle = self.inner.as_raw();
run_operation(move |op| {
match unsafe { HcsTerminateProcess(*handle, op, &opts_w) } {
Ok(()) => windows::core::HRESULT(0),
Err(e) => e.code(),
}
})
.await?;
Ok(())
}
pub async fn modify(&self, modification_json: &str) -> HcsResult<()> {
let mod_w = HSTRING::from(modification_json);
let handle = self.inner.as_raw();
run_operation(move |op| {
match unsafe { HcsModifyProcess(*handle, op, &mod_w) } {
Ok(()) => windows::core::HRESULT(0),
Err(e) => e.code(),
}
})
.await?;
Ok(())
}
pub async fn resize_console(&self, cols: u16, rows: u16) -> HcsResult<()> {
let json = serde_json::to_string(&serde_json::json!({
"ConsoleSize": {
"Width": cols,
"Height": rows,
}
}))?;
self.modify(&json).await
}
pub async fn properties(&self, property_query_json: &str) -> HcsResult<String> {
let query_w = HSTRING::from(property_query_json);
let handle = self.inner.as_raw();
run_operation(move |op| {
match unsafe { HcsGetProcessProperties(*handle, op, &query_w) } {
Ok(()) => windows::core::HRESULT(0),
Err(e) => e.code(),
}
})
.await
}
}