use crate::{Error, Monitor, Result};
use std::ptr::null_mut;
use windows::{
core::Interface,
Win32::{
Foundation::HMODULE,
Graphics::{
Direct3D::D3D_DRIVER_TYPE_UNKNOWN,
Direct3D11::{
D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, D3D11_CREATE_DEVICE_FLAG,
D3D11_SDK_VERSION,
},
Dxgi::{CreateDXGIFactory1, IDXGIAdapter1, IDXGIFactory1, IDXGIOutput1},
},
},
};
#[derive(Debug, Clone)]
pub struct Scanner {
next_adapter_index: u32,
next_output_index: u32,
factory: IDXGIFactory1,
adapter: IDXGIAdapter1,
device: ID3D11Device,
device_context: ID3D11DeviceContext,
}
impl Scanner {
pub fn new() -> Result<Self> {
let factory = unsafe { CreateDXGIFactory1::<IDXGIFactory1>() }
.map_err(Error::from_win_err(stringify!(CreateDXGIFactory1)))?;
let adapter_index = 0;
let (adapter, device, device_context) = get_adapter(&factory, adapter_index)?;
Ok(Self {
next_adapter_index: adapter_index + 1,
next_output_index: 0,
factory,
adapter,
device,
device_context,
})
}
fn get_current_ctx(&mut self) -> Option<Monitor> {
let output_index = self.next_output_index;
self.next_output_index += 1;
let output = unsafe { self.adapter.EnumOutputs(output_index) }.ok()?;
let output = output.cast::<IDXGIOutput1>().unwrap();
let output_duplication = unsafe { output.DuplicateOutput(&self.device) }.ok()?;
Some(Monitor::new(
self.device.clone(),
self.device_context.clone(),
output,
output_duplication,
))
}
}
impl Iterator for Scanner {
type Item = Monitor;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(ctx) = self.get_current_ctx() {
return Some(ctx);
}
let adapter_index = self.next_adapter_index;
self.next_adapter_index += 1;
let Ok((adapter, device, device_context)) = get_adapter(&self.factory, adapter_index) else {
break;
};
self.adapter = adapter;
self.device = device;
self.device_context = device_context;
self.next_output_index = 0;
}
None
}
}
fn get_adapter(
factory: &IDXGIFactory1,
adapter_index: u32,
) -> Result<(IDXGIAdapter1, ID3D11Device, ID3D11DeviceContext)> {
let adapter = unsafe { factory.EnumAdapters1(adapter_index) }
.map_err(Error::from_win_err(stringify!(IDXGIFactory1.EnumAdapters1)))?;
let mut device: Option<ID3D11Device> = None;
let mut device_context: Option<ID3D11DeviceContext> = None;
unsafe {
D3D11CreateDevice(
&adapter,
D3D_DRIVER_TYPE_UNKNOWN,
HMODULE(null_mut()),
D3D11_CREATE_DEVICE_FLAG(0),
None,
D3D11_SDK_VERSION,
Some(&mut device),
None,
Some(&mut device_context),
)
}
.map_err(Error::from_win_err(stringify!(D3D11CreateDevice)))?;
Ok((adapter, device.unwrap(), device_context.unwrap()))
}
#[cfg(test)]
mod tests {
use super::*;
use serial_test::serial;
#[test]
#[serial]
fn manager() {
let mut factory = Scanner::new().unwrap();
assert!(factory.next().is_some());
}
}