Evan's Blog
EvanZhu0721 / 公开仓库

SBMS

镜像已同步

SBMS complete the calculation rules for the default logical desktop topology relationship and the physical dimensions of the displays in the Windows multi-screen collaboration system.

上游 GitHub
READ-ONLY MIRROR

README、源码与 Release 已保存到本站;源码视图固定到 commit a37d6c4b。

main/ root / src
a37d6c4b· 固定源码快照
src/virtual_display.rs7.2 KB
1use std::ffi::c_void;
2use std::sync::atomic::{AtomicBool, Ordering};
3use std::sync::{Arc, Condvar, Mutex};
4use std::time::{Duration, Instant};
5
6use windows::Win32::Devices::Enumeration::Pnp::{
7 HSWDEVICE, SW_DEVICE_CREATE_INFO, SWDeviceCapabilitiesDriverRequired,
8 SWDeviceCapabilitiesRemovable, SWDeviceCapabilitiesSilentInstall, SwDeviceClose,
9 SwDeviceCreate,
10};
11use windows::Win32::Security::SECURITY_DESCRIPTOR;
12use windows::core::{Error, GUID, HRESULT, PCWSTR, Result, w};
13
14const CREATE_TIMEOUT: Duration = Duration::from_secs(10);
15const CANCEL_POLL_INTERVAL: Duration = Duration::from_millis(50);
16const CONTAINER_ID: GUID = GUID::from_u128(0x71d2c4b2_0e4e_4a65_93c5_80c9c616f42c);
17
18struct CreationState {
19 result: Mutex<Option<std::result::Result<String, HRESULT>>>,
20 changed: Condvar,
21}
22
23enum CreationWait {
24 Completed(std::result::Result<String, HRESULT>),
25 Cancelled,
26 TimedOut,
27}
28
29impl CreationState {
30 fn new() -> Self {
31 Self {
32 result: Mutex::new(None),
33 changed: Condvar::new(),
34 }
35 }
36}
37
38pub struct VirtualDisplay {
39 handle: HSWDEVICE,
40}
41
42impl VirtualDisplay {
43 pub fn create() -> Result<Self> {
44 let cancel = AtomicBool::new(false);
45 Self::create_cancellable(&cancel)
46 }
47
48 pub(crate) fn create_cancellable(cancel: &AtomicBool) -> Result<Self> {
49 let hardware_ids = wide_multi_string(&["SBMS\\IndirectDisplay"]);
50 let state = Arc::new(CreationState::new());
51
52 let create_info = SW_DEVICE_CREATE_INFO {
53 cbSize: size_of::<SW_DEVICE_CREATE_INFO>() as u32,
54 pszInstanceId: w!("VirtualDisplay-01"),
55 pszzHardwareIds: PCWSTR(hardware_ids.as_ptr()),
56 pszzCompatibleIds: PCWSTR::null(),
57 pContainerId: &CONTAINER_ID,
58 CapabilityFlags: (SWDeviceCapabilitiesRemovable.0
59 | SWDeviceCapabilitiesSilentInstall.0
60 | SWDeviceCapabilitiesDriverRequired.0) as u32,
61 pszDeviceDescription: w!("SBMS Virtual Display"),
62 pszDeviceLocation: w!("Software device"),
63 pSecurityDescriptor: std::ptr::null::<SECURITY_DESCRIPTOR>(),
64 };
65
66 // One Arc reference belongs to the callback. This keeps the context alive
67 // even if our bounded wait expires before Windows invokes it.
68 let callback_state = Arc::into_raw(Arc::clone(&state));
69
70 // SAFETY: create_info remains valid for this call. callback_state is an Arc
71 // raw pointer reserved for the one-shot callback.
72 let create_result = unsafe {
73 SwDeviceCreate(
74 w!("SBMS"),
75 w!("HTREE\\ROOT\\0"),
76 &create_info,
77 None,
78 Some(device_created),
79 Some(callback_state.cast::<c_void>()),
80 )
81 };
82 let handle = match create_result {
83 Ok(handle) => handle,
84 Err(error) => {
85 // No callback is scheduled when SwDeviceCreate itself fails.
86 // SAFETY: callback_state came from Arc::into_raw above.
87 unsafe { drop(Arc::from_raw(callback_state)) };
88 return Err(error);
89 }
90 };
91
92 match wait_for_creation(&state, cancel, CREATE_TIMEOUT) {
93 CreationWait::Completed(Ok(_)) => Ok(Self { handle }),
94 CreationWait::Completed(Err(hr)) => {
95 // SAFETY: handle came from a successful SwDeviceCreate call.
96 unsafe { SwDeviceClose(handle) };
97 Err(Error::from_hresult(hr))
98 }
99 CreationWait::Cancelled => {
100 // SAFETY: handle came from a successful SwDeviceCreate call.
101 unsafe { SwDeviceClose(handle) };
102 Err(Error::from_hresult(HRESULT(0x800704C7_u32 as i32)))
103 }
104 CreationWait::TimedOut => {
105 // SAFETY: handle came from a successful SwDeviceCreate call.
106 unsafe { SwDeviceClose(handle) };
107 Err(Error::from_hresult(HRESULT(0x800705B4_u32 as i32)))
108 }
109 }
110 }
111}
112
113fn wait_for_creation(
114 state: &CreationState,
115 cancel: &AtomicBool,
116 timeout: Duration,
117) -> CreationWait {
118 let deadline = Instant::now() + timeout;
119 let mut result = state.result.lock().expect("creation mutex poisoned");
120 loop {
121 if let Some(outcome) = result.take() {
122 return CreationWait::Completed(outcome);
123 }
124 if cancel.load(Ordering::Acquire) {
125 return CreationWait::Cancelled;
126 }
127 let now = Instant::now();
128 if now >= deadline {
129 return CreationWait::TimedOut;
130 }
131 let wait = (deadline - now).min(CANCEL_POLL_INTERVAL);
132 let (updated, _) = state
133 .changed
134 .wait_timeout(result, wait)
135 .expect("creation mutex poisoned");
136 result = updated;
137 }
138}
139
140impl Drop for VirtualDisplay {
141 fn drop(&mut self) {
142 // SAFETY: this type uniquely owns the HSWDEVICE returned by SwDeviceCreate.
143 unsafe { SwDeviceClose(self.handle) };
144 }
145}
146
147unsafe extern "system" fn device_created(
148 _device: HSWDEVICE,
149 create_result: HRESULT,
150 context: *const c_void,
151 device_instance_id: PCWSTR,
152) {
153 // SAFETY: create() passes one Arc strong reference exclusively to this
154 // one-shot callback.
155 let state = unsafe { Arc::from_raw(context as *const CreationState) };
156 let outcome = if create_result.is_ok() {
157 // SAFETY: Windows supplies a null-terminated instance ID.
158 unsafe { device_instance_id.to_string() }.map_err(|_| HRESULT(0x80070057_u32 as i32))
159 } else {
160 Err(create_result)
161 };
162
163 *state.result.lock().expect("creation mutex poisoned") = Some(outcome);
164 state.changed.notify_one();
165}
166
167fn wide_multi_string(values: &[&str]) -> Vec<u16> {
168 let mut result = Vec::new();
169 for value in values {
170 result.extend(value.encode_utf16());
171 result.push(0);
172 }
173 result.push(0);
174 result
175}
176
177#[cfg(test)]
178mod tests {
179 use super::{CreationState, CreationWait, wait_for_creation};
180 use std::sync::atomic::{AtomicBool, Ordering};
181 use std::time::{Duration, Instant};
182
183 #[test]
184 fn creation_wait_prefers_a_completed_callback_over_cancellation() {
185 let state = CreationState::new();
186 *state.result.lock().unwrap() = Some(Ok("device".into()));
187 let cancel = AtomicBool::new(true);
188 assert!(matches!(
189 wait_for_creation(&state, &cancel, Duration::from_secs(1)),
190 CreationWait::Completed(Ok(id)) if id == "device"
191 ));
192 }
193
194 #[test]
195 fn creation_wait_observes_cancellation_without_waiting_for_timeout() {
196 let state = CreationState::new();
197 let cancel = AtomicBool::new(true);
198 let started = Instant::now();
199 assert!(matches!(
200 wait_for_creation(&state, &cancel, Duration::from_secs(1)),
201 CreationWait::Cancelled
202 ));
203 assert!(started.elapsed() < Duration::from_millis(100));
204 cancel.store(false, Ordering::Release);
205 }
206
207 #[test]
208 fn creation_wait_reports_timeout() {
209 let state = CreationState::new();
210 let cancel = AtomicBool::new(false);
211 assert!(matches!(
212 wait_for_creation(&state, &cancel, Duration::from_millis(1)),
213 CreationWait::TimedOut
214 ));
215 }
216}
217