use windows_sys::Win32::Foundation::{CloseHandle, FALSE, GetLastError, HANDLE};
use windows_sys::Win32::System::Memory::{
FILE_MAP_READ, MEM_COMMIT, MEMORY_BASIC_INFORMATION, MEMORY_MAPPED_VIEW_ADDRESS, MapViewOfFile,
OpenFileMappingW, UnmapViewOfFile, VirtualQuery,
};
pub struct SharedMemRegion {
h_map: HANDLE,
pub view: MEMORY_MAPPED_VIEW_ADDRESS,
}
impl SharedMemRegion {
pub fn open(name: &str) -> Result<Self, String> {
unsafe {
let wide: Vec<u16> = name.encode_utf16().chain(std::iter::once(0)).collect();
let h_map = OpenFileMappingW(FILE_MAP_READ, FALSE, wide.as_ptr());
if h_map.is_null() {
let err = GetLastError();
return Err(format!(
"OpenFileMappingW failed for '{}' (error {})",
name, err
));
}
let view = MapViewOfFile(h_map, FILE_MAP_READ, 0, 0, 0);
if view.Value.is_null() {
let err = GetLastError();
CloseHandle(h_map);
return Err(format!("MapViewOfFile failed (error {})", err));
}
Ok(Self { h_map, view })
}
}
pub fn as_ptr(&self) -> *const u8 {
self.view.Value as *const u8
}
pub fn len(&self) -> usize {
unsafe {
let mut info: MEMORY_BASIC_INFORMATION = std::mem::zeroed();
let ret = VirtualQuery(
self.view.Value,
&mut info,
std::mem::size_of::<MEMORY_BASIC_INFORMATION>(),
);
if ret == 0 || info.State != MEM_COMMIT {
return 0;
}
info.RegionSize
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[doc(hidden)]
pub unsafe fn new_mock(ptr: *mut std::ffi::c_void) -> Self {
Self {
h_map: 0 as _,
view: MEMORY_MAPPED_VIEW_ADDRESS { Value: ptr },
}
}
}
impl Drop for SharedMemRegion {
fn drop(&mut self) {
unsafe {
if !self.view.Value.is_null() {
UnmapViewOfFile(self.view);
}
if !self.h_map.is_null() {
CloseHandle(self.h_map);
}
}
}
}