use crate::windows_native::error::{check_config, WinError, WinResult};
use crate::windows_native::string::U16Str;
use crate::windows_native::types::{DeviceProperty, PropertyKey};
use std::ptr::null_mut;
use windows_sys::Win32::Devices::DeviceAndDriverInstallation::{
CM_Get_DevNode_PropertyW, CM_Get_Parent, CM_Locate_DevNodeW, CM_LOCATE_DEVNODE_NORMAL,
CR_BUFFER_SMALL, CR_SUCCESS,
};
#[repr(transparent)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct DevNode(u32);
impl DevNode {
pub fn from_device_id(device_id: &U16Str) -> WinResult<Self> {
let mut node = 0;
let cr =
unsafe { CM_Locate_DevNodeW(&mut node, device_id.as_ptr(), CM_LOCATE_DEVNODE_NORMAL) };
check_config(cr, CR_SUCCESS)?;
Ok(Self(node))
}
pub fn parent(self) -> WinResult<Self> {
let mut parent = 0;
let cr = unsafe { CM_Get_Parent(&mut parent, self.0, 0) };
check_config(cr, CR_SUCCESS)?;
Ok(Self(parent))
}
fn get_property_size<T: DeviceProperty>(
self,
property_key: impl PropertyKey,
) -> WinResult<usize> {
let mut property_type = 0;
let mut len = 0;
let cr = unsafe {
CM_Get_DevNode_PropertyW(
self.0,
property_key.as_ptr(),
&mut property_type,
null_mut(),
&mut len,
0,
)
};
check_config(cr, CR_BUFFER_SMALL)?;
ensure!(
property_type == T::TYPE,
Err(WinError::WrongPropertyDataType)
);
Ok(len as usize)
}
pub fn get_property<T: DeviceProperty>(self, property_key: impl PropertyKey) -> WinResult<T> {
let size = self.get_property_size::<T>(property_key)?;
let mut property = T::create_sized(size);
let mut property_type = 0;
let mut len = size as u32;
let cr = unsafe {
CM_Get_DevNode_PropertyW(
self.0,
property_key.as_ptr(),
&mut property_type,
property.as_ptr_mut(),
&mut len,
0,
)
};
check_config(cr, CR_SUCCESS)?;
ensure!(size == len as usize, Err(WinError::UnexpectedReturnSize));
property.validate();
Ok(property)
}
}