Skip to main content
Glama
windows.rs4.55 kB
use super::{Screenshot, ScreenshotError}; use tauri::{Runtime, WebviewWindow}; /// Windows-specific screenshot implementation using WebView2's CapturePreview /// /// This implementation captures only the visible viewport. /// WebView2's CapturePreview API naturally captures just the viewport. pub fn capture_viewport<R: Runtime>( window: &WebviewWindow<R>, ) -> Result<Screenshot, ScreenshotError> { #[cfg(target_os = "windows")] { use std::sync::mpsc; use webview2_com::{ CapturePreviewCompletedHandler, Microsoft::Web::WebView2::Win32::COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT_PNG, }; use windows::Win32::Foundation::HGLOBAL; use windows::Win32::System::Com::IStream; use windows::Win32::System::Com::StructuredStorage::CreateStreamOnHGlobal; let (tx, rx) = mpsc::channel::<Result<Screenshot, ScreenshotError>>(); window .with_webview(move |webview| { unsafe { // Get ICoreWebView2 from Tauri's webview handle let controller = webview.controller(); let core_webview = controller.CoreWebView2().unwrap(); // Create memory stream for PNG output let stream: IStream = CreateStreamOnHGlobal(HGLOBAL::default(), true).unwrap(); let stream_clone = stream.clone(); // Use webview2-com's pre-built completion handler let handler = CapturePreviewCompletedHandler::create(Box::new(move |result| { let screenshot_result = match result { Ok(()) => { // SAFETY: read_stream_to_vec requires the stream to be valid, // which is guaranteed by the CapturePreview completion handler match read_stream_to_vec(&stream_clone) { Ok(data) => Ok(Screenshot { data }), Err(e) => Err(e), } } Err(e) => Err(ScreenshotError::CaptureFailed(format!( "CapturePreview failed: {}", e ))), }; let _ = tx.send(screenshot_result); Ok(()) })); // Capture viewport as PNG let _ = core_webview.CapturePreview( COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT_PNG, &stream, &handler, ); } }) .map_err(|e| { ScreenshotError::CaptureFailed(format!("Failed to access webview: {}", e)) })?; // Wait for result match rx.recv_timeout(std::time::Duration::from_secs(10)) { Ok(result) => result, Err(_) => Err(ScreenshotError::Timeout), } } #[cfg(not(target_os = "windows"))] { Err(ScreenshotError::PlatformUnsupported) } } /// Read all bytes from an IStream /// /// # Safety /// The stream must be valid and readable. #[cfg(target_os = "windows")] unsafe fn read_stream_to_vec( stream: &windows::Win32::System::Com::IStream, ) -> Result<Vec<u8>, ScreenshotError> { use windows::Win32::System::Com::{STREAM_SEEK_END, STREAM_SEEK_SET}; // Seek to beginning stream .Seek(0, STREAM_SEEK_SET, None) .map_err(|e| ScreenshotError::CaptureFailed(format!("Failed to seek stream: {}", e)))?; // Get stream size by seeking to end let mut end_pos: u64 = 0; stream .Seek(0, STREAM_SEEK_END, Some(&mut end_pos)) .map_err(|e| ScreenshotError::CaptureFailed(format!("Failed to get stream size: {}", e)))?; // Seek back to start stream .Seek(0, STREAM_SEEK_SET, None) .map_err(|e| ScreenshotError::CaptureFailed(format!("Failed to seek stream: {}", e)))?; // Read data let mut buffer = vec![0u8; end_pos as usize]; let mut bytes_read: u32 = 0; stream .Read( buffer.as_mut_ptr() as *mut _, buffer.len() as u32, Some(&mut bytes_read), ) .ok() .map_err(|e| ScreenshotError::CaptureFailed(format!("Failed to read stream: {}", e)))?; buffer.truncate(bytes_read as usize); Ok(buffer) }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hypothesi/mcp-server-tauri'

If you have feedback or need assistance with the MCP directory API, please join our Discord server