Capturing Remote Desktop (RDP) Screen Content in Rust on Windows Server

Louis Beaumont 0 Reputation points
2024-11-17T23:20:51+00:00

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:

  1. What is the recommended API/approach to capture RDP session screens?
  2. Do we need specific permissions or configurations on Windows Server?
  3. 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.

Remote Desktop
Remote Desktop
A Microsoft app that connects remotely to computers and to virtual apps and desktops.
4,612 questions
0 comments No comments
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.