5,099 questions
Capturing Remote Desktop (RDP) Screen Content in Rust on Windows Server
Louis Beaumont
0
Reputation points
I'm developing an open-source screen capture application in Rust that needs to capture screen content from Remote Desktop sessions on Windows Server 2022. Our setup:
- Windows Server 2022 hosting multiple RDP sessions
- Multiple users connecting via RDP from thin clients
- Using Rust with
xcap
crate for screen capture - Need to capture individual user session screens
This works for local screens but fails to capture RDP session content.
Questions:
- What is the recommended API/approach to capture RDP session screens?
- Do we need specific permissions or configurations on Windows Server?
- Are there any RDP-specific APIs we should use instead of standard screen capture methods?
I've been diving into windows-rs
lib to do so. This is my current WIP code:
pub async fn capture_rdp_session(session_id: &str) -> Result<DynamicImage> {
#[cfg(target_os = "windows")]
{
use windows::Win32::System::RemoteDesktop::{
WTSQuerySessionInformationW, WTSVirtualChannelQuery, WTS_CURRENT_SERVER_HANDLE,
WTS_VIRTUAL_CLASS, WTSEnumerateSessionsW, WTS_SESSION_INFOW,
};
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
// First find the correct session ID
let mut session_count: u32 = 0;
let mut sessions_ptr = std::ptr::null_mut();
unsafe {
WTSEnumerateSessionsW(
WTS_CURRENT_SERVER_HANDLE,
0,
1,
&mut sessions_ptr,
&mut session_count,
)?;
let sessions = std::slice::from_raw_parts(
sessions_ptr as *const WTS_SESSION_INFOW,
session_count as usize,
);
println!("Sessions: {:?}", sessions);
// Find matching session
// let target_session = sessions.iter().find(|s| {
// let session_name = unsafe {
// let slice = s.pWinStationName.as_wide();
// String::from_utf16_lossy(slice)
// };
// session_name == session_id
// }).ok_or_else(|| anyhow!("Session not found"))?;
let target_session = sessions[0];
// Query session buffer
let mut buffer_size: u32 = 0;
let mut buffer_ptr = std::ptr::null_mut();
WTSVirtualChannelQuery(
WTS_CURRENT_SERVER_HANDLE,
WTS_VIRTUAL_CLASS(target_session.SessionId as i32),
&mut buffer_ptr,
&mut buffer_size,
)?;
if buffer_ptr.is_null() {
return Err(anyhow!("Failed to get session buffer"));
}
// Convert buffer to image
let buffer_slice = std::slice::from_raw_parts(
buffer_ptr as *const u8,
buffer_size as usize
);
let buffer_vec = buffer_slice.to_vec();
// Free WTS memory
WTSFreeMemory(buffer_ptr);
WTSFreeMemory(sessions_ptr as *mut _);
// Create image from buffer
let width = (buffer_size as f64).sqrt() as u32;
let image = DynamicImage::ImageRgb8(
ImageBuffer::from_raw(width, width, buffer_vec)
.ok_or_else(|| anyhow!("Failed to create image buffer"))?
);
Ok(image)
}
}
#[cfg(not(target_os = "windows"))]
{
Err(anyhow!("RDP capture only supported on Windows"))
}
}
Any guidance on the correct Windows APIs or Rust crates for this specific use case would be greatly appreciated.
Windows for business | Windows Client for IT Pros | User experience | Remote desktop services and terminal services
Sign in to answer