Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion crates/recording/src/sources/screen_capture/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,14 @@ impl output_pipeline::VideoSource for VideoSource {
item
}
Err(e) => {
error!("Failed to create GraphicsCaptureItem on capture thread: {}", e);
error!(
"Failed to create GraphicsCaptureItem on capture thread: {}. \
If you're running Windows 10 build 18363 (version 1903), this may be due to \
a permissions issue or a known compatibility issue with the Graphics Capture API. \
Please ensure the application has screen capture permissions, or try updating to \
a newer version of Windows 10 or Windows 11.",
e
);
let _ = error_tx.send(anyhow!("Failed to create GraphicsCaptureItem: {}", e));
return;
}
Expand Down
46 changes: 42 additions & 4 deletions crates/scap-targets/src/platform/win.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{ffi::OsString, mem, os::windows::ffi::OsStringExt, path::PathBuf, str::FromStr};
use tracing::error;
use std::{ffi::OsString, mem, os::windows::ffi::OsStringExt, panic, path::PathBuf, str::FromStr};
use tracing::{error, warn};
use windows::{
Graphics::Capture::GraphicsCaptureItem,
Win32::{
Expand Down Expand Up @@ -258,7 +258,26 @@ impl DisplayImpl {

pub fn try_as_capture_item(&self) -> windows::core::Result<GraphicsCaptureItem> {
let interop = windows::core::factory::<GraphicsCaptureItem, IGraphicsCaptureItemInterop>()?;
unsafe { interop.CreateForMonitor(self.0) }

// Wrap the unsafe FFI call in catch_unwind to handle C++ exceptions that may cross the FFI boundary.
// On Windows 10 build 18363 (the minimum supported version), the Graphics Capture API can throw
// C++ exceptions instead of returning proper error codes, which would otherwise crash the application.
let monitor = self.0;
match panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe {
interop.CreateForMonitor(monitor)
})) {
Ok(result) => result,
Err(panic_info) => {
// Log the panic to help diagnose issues on older Windows versions
warn!(
"Graphics Capture API panicked when creating capture item for monitor. \
This may indicate a permissions issue or incompatibility with Windows 10 build 18363. \
Panic info: {:?}",
panic_info
);
Err(windows::core::Error::from_win32())
}
}
}
}

Expand Down Expand Up @@ -1148,7 +1167,26 @@ impl WindowImpl {

pub fn try_as_capture_item(&self) -> windows::core::Result<GraphicsCaptureItem> {
let interop = windows::core::factory::<GraphicsCaptureItem, IGraphicsCaptureItemInterop>()?;
unsafe { interop.CreateForWindow(self.0) }

// Wrap the unsafe FFI call in catch_unwind to handle C++ exceptions that may cross the FFI boundary.
// On Windows 10 build 18363 (the minimum supported version), the Graphics Capture API can throw
// C++ exceptions instead of returning proper error codes, which would otherwise crash the application.
let window = self.0;
match panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe {
interop.CreateForWindow(window)
})) {
Ok(result) => result,
Err(panic_info) => {
// Log the panic to help diagnose issues on older Windows versions
warn!(
"Graphics Capture API panicked when creating capture item for window. \
This may indicate a permissions issue or incompatibility with Windows 10 build 18363. \
Panic info: {:?}",
panic_info
);
Err(windows::core::Error::from_win32())
}
}
}
}

Expand Down
Loading