rusty_duplication/
scanner.rs1use crate::{Error, Monitor, Result};
2use std::ptr::null_mut;
3use windows::{
4 core::Interface,
5 Win32::{
6 Foundation::HMODULE,
7 Graphics::{
8 Direct3D::D3D_DRIVER_TYPE_UNKNOWN,
9 Direct3D11::{
10 D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, D3D11_CREATE_DEVICE_FLAG,
11 D3D11_SDK_VERSION,
12 },
13 Dxgi::{CreateDXGIFactory1, IDXGIAdapter1, IDXGIFactory1, IDXGIOutput1},
14 },
15 },
16};
17
18#[derive(Debug, Clone)]
29pub struct Scanner {
30 next_adapter_index: u32,
31 next_output_index: u32,
32 factory: IDXGIFactory1,
33 adapter: IDXGIAdapter1,
34 device: ID3D11Device,
35 device_context: ID3D11DeviceContext,
36}
37
38impl Scanner {
39 pub fn new() -> Result<Self> {
42 let factory = unsafe { CreateDXGIFactory1::<IDXGIFactory1>() }
43 .map_err(Error::from_win_err(stringify!(CreateDXGIFactory1)))?;
44
45 let adapter_index = 0;
46 let (adapter, device, device_context) = get_adapter(&factory, adapter_index)?;
47
48 Ok(Self {
49 next_adapter_index: adapter_index + 1,
50 next_output_index: 0,
51 factory,
52 adapter,
53 device,
54 device_context,
55 })
56 }
57
58 fn get_current_ctx(&mut self) -> Option<Monitor> {
59 let output_index = self.next_output_index;
60 self.next_output_index += 1;
61
62 let output = unsafe { self.adapter.EnumOutputs(output_index) }.ok()?;
64 let output = output.cast::<IDXGIOutput1>().unwrap();
65 let output_duplication = unsafe { output.DuplicateOutput(&self.device) }.ok()?;
66 Some(Monitor::new(
67 self.device.clone(),
68 self.device_context.clone(),
69 output,
70 output_duplication,
71 ))
72 }
73}
74
75impl Iterator for Scanner {
76 type Item = Monitor;
77
78 fn next(&mut self) -> Option<Self::Item> {
79 loop {
80 if let Some(ctx) = self.get_current_ctx() {
81 return Some(ctx);
82 }
83
84 let adapter_index = self.next_adapter_index;
86 self.next_adapter_index += 1;
87 let Ok((adapter, device, device_context)) = get_adapter(&self.factory, adapter_index) else {
88 break;
89 };
90 self.adapter = adapter;
91 self.device = device;
92 self.device_context = device_context;
93 self.next_output_index = 0;
94 }
95
96 None
97 }
98}
99
100fn get_adapter(
101 factory: &IDXGIFactory1,
102 adapter_index: u32,
103) -> Result<(IDXGIAdapter1, ID3D11Device, ID3D11DeviceContext)> {
104 let adapter = unsafe { factory.EnumAdapters1(adapter_index) }
105 .map_err(Error::from_win_err(stringify!(IDXGIFactory1.EnumAdapters1)))?;
106
107 let mut device: Option<ID3D11Device> = None;
108 let mut device_context: Option<ID3D11DeviceContext> = None;
109
110 unsafe {
111 D3D11CreateDevice(
112 &adapter,
113 D3D_DRIVER_TYPE_UNKNOWN,
114 HMODULE(null_mut()),
115 D3D11_CREATE_DEVICE_FLAG(0),
116 None,
117 D3D11_SDK_VERSION,
118 Some(&mut device),
119 None,
120 Some(&mut device_context),
121 )
122 }
123 .map_err(Error::from_win_err(stringify!(D3D11CreateDevice)))?;
124
125 Ok((adapter, device.unwrap(), device_context.unwrap()))
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use serial_test::serial;
132
133 #[test]
134 #[serial]
135 fn manager() {
136 let mut factory = Scanner::new().unwrap();
137 assert!(factory.next().is_some());
138 }
139}