rusty_duplication/capturer/
shared.rs1use super::CapturerBuffer;
2use crate::{Capturer, Error, Monitor, Result};
3use std::ffi::CString;
4use std::slice;
5use windows::{
6 core::PCSTR,
7 Win32::{
8 Foundation::{CloseHandle, HANDLE, INVALID_HANDLE_VALUE},
9 System::Memory::{
10 CreateFileMappingA, MapViewOfFile, OpenFileMappingA, UnmapViewOfFile, FILE_MAP_ALL_ACCESS,
11 MEMORY_MAPPED_VIEW_ADDRESS, PAGE_READWRITE,
12 },
13 },
14};
15
16#[derive(Debug)]
18pub struct SharedMemory {
19 ptr: *mut u8,
20 len: usize,
21 file: HANDLE,
22}
23
24impl CapturerBuffer for SharedMemory {
25 #[inline]
26 fn as_bytes(&self) -> &[u8] {
27 unsafe { slice::from_raw_parts(self.ptr, self.len) }
28 }
29
30 #[inline]
31 fn as_bytes_mut(&mut self) -> &mut [u8] {
32 unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
33 }
34}
35
36impl Drop for SharedMemory {
37 fn drop(&mut self) {
38 unsafe {
40 UnmapViewOfFile(MEMORY_MAPPED_VIEW_ADDRESS {
41 Value: self.ptr as _,
42 })
43 .ok();
44 CloseHandle(self.file).ok();
45 }
46 }
47}
48
49pub type SharedMemoryCapturer = Capturer<SharedMemory>;
53
54impl SharedMemoryCapturer {
55 pub fn create(monitor: Monitor, name: &str) -> Result<Self> {
57 Self::new(monitor, move |len| unsafe {
58 let file = CreateFileMappingA(
59 INVALID_HANDLE_VALUE,
60 None,
61 PAGE_READWRITE,
62 0,
63 len as u32,
64 str_to_pc_str(name),
65 )
66 .map_err(Error::from_win_err(stringify!(CreateFileMappingA)))?;
67
68 Ok(SharedMemory {
69 ptr: map_view_of_file(file, len)?,
70 len,
71 file,
72 })
73 })
74 }
75
76 pub fn open(monitor: Monitor, name: &str) -> Result<Self> {
78 Self::new(monitor, move |len| unsafe {
79 let file = OpenFileMappingA(FILE_MAP_ALL_ACCESS.0, false, str_to_pc_str(name))
80 .map_err(Error::from_win_err(stringify!(OpenFileMappingA)))?;
81
82 Ok(SharedMemory {
83 ptr: map_view_of_file(file, len)?,
84 len,
85 file,
86 })
87 })
88 }
89}
90
91unsafe fn map_view_of_file(file: HANDLE, buffer_size: usize) -> Result<*mut u8> {
92 let buffer_ptr = MapViewOfFile(
93 file, FILE_MAP_ALL_ACCESS, 0,
96 0,
97 buffer_size,
98 );
99
100 if buffer_ptr.Value.is_null() {
101 CloseHandle(file).ok();
102 return Err(Error::last_win_err(stringify!(MapViewOfFile)));
103 }
104
105 Ok(buffer_ptr.Value as *mut u8)
106}
107
108#[inline]
109fn str_to_pc_str(s: &str) -> PCSTR {
110 let c_str = CString::new(s).unwrap(); PCSTR(c_str.as_ptr() as _)
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use crate::{FrameInfoExt, Scanner};
118 use serial_test::serial;
119 use std::{thread, time::Duration};
120
121 #[test]
122 #[serial]
123 fn shared_capturer() {
124 let monitor = Scanner::new().unwrap().next().unwrap();
125 let mut capturer = SharedMemoryCapturer::create(monitor, "RustyDuplicationTest").unwrap();
126
127 thread::sleep(Duration::from_millis(50));
129
130 let info = capturer.capture().unwrap();
131 assert!(info.desktop_updated());
132
133 assert!(!capturer.buffer.as_bytes().iter().all(|&n| n == 0));
135
136 thread::sleep(Duration::from_millis(50));
137
138 let (frame_info, pointer_shape_info) = capturer.capture_with_pointer_shape().unwrap();
140 if frame_info.pointer_shape_updated() {
141 assert!(pointer_shape_info.is_some());
142 assert!(!capturer.pointer_shape_buffer.iter().all(|&n| n == 0));
144 } else {
145 panic!(
146 "Move your mouse to change the shape of the cursor during the test to check mouse capture"
147 );
148 }
149 }
150}