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.
文件
../ bininputuiconfig.rs81.2 KBcontrol.rs4.1 KBcontroller.rs43.6 KBdiagnostics.rs24.2 KBdisplay.rs29.8 KBgeometry.rs21.4 KBgpu_renderer.rs37.4 KBinput.rs79.7 KBlaunch_broker.rs10.3 KBlib.rs350 Blimits.rs714 Bmain.rs24.4 KBmapping.rs46.5 KBnetwork.rs9.2 KBrenderer.rs20.6 KBsession_gate.rs14.9 KBsunshine.rs12.2 KBui.rs68.5 KBvirtual_display.rs7.2 KBwin32_flyout.rs3.4 KBwin32_tray.rs22.3 KBwindow_migration.rs43.8 KBsrc/virtual_display.rs7.2 KB
1
use std::ffi::c_void;2
use std::sync::atomic::{AtomicBool, Ordering};3
use std::sync::{Arc, Condvar, Mutex};4
use std::time::{Duration, Instant};5
6
use windows::Win32::Devices::Enumeration::Pnp::{7
HSWDEVICE, SW_DEVICE_CREATE_INFO, SWDeviceCapabilitiesDriverRequired,8
SWDeviceCapabilitiesRemovable, SWDeviceCapabilitiesSilentInstall, SwDeviceClose,9
SwDeviceCreate,10
};11
use windows::Win32::Security::SECURITY_DESCRIPTOR;12
use windows::core::{Error, GUID, HRESULT, PCWSTR, Result, w};13
14
const CREATE_TIMEOUT: Duration = Duration::from_secs(10);15
const CANCEL_POLL_INTERVAL: Duration = Duration::from_millis(50);16
const CONTAINER_ID: GUID = GUID::from_u128(0x71d2c4b2_0e4e_4a65_93c5_80c9c616f42c);17
18
struct CreationState {19
result: Mutex<Option<std::result::Result<String, HRESULT>>>,20
changed: Condvar,21
}22
23
enum CreationWait {24
Completed(std::result::Result<String, HRESULT>),25
Cancelled,26
TimedOut,27
}28
29
impl CreationState {30
fn new() -> Self {31
Self {32
result: Mutex::new(None),33
changed: Condvar::new(),34
}35
}36
}37
38
pub struct VirtualDisplay {39
handle: HSWDEVICE,40
}41
42
impl 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.059
| SWDeviceCapabilitiesSilentInstall.060
| 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 alive67
// 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 Arc71
// 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
113
fn 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, _) = state133
.changed134
.wait_timeout(result, wait)135
.expect("creation mutex poisoned");136
result = updated;137
}138
}139
140
impl 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
147
unsafe 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 this154
// 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
167
fn 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
result175
}176
177
#[cfg(test)]178
mod 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::Cancelled202
));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::TimedOut214
));215
}216
}217