use windows::{
Win32::Foundation::HANDLE,
Win32::System::Memory::{VirtualQueryEx, MEMORY_BASIC_INFORMATION},
};
use std::sync::OnceLock;
static REGION_CACHE: OnceLock<std::sync::Mutex<std::collections::HashMap<usize, Vec<(usize, usize)>>>> =
OnceLock::new();
pub(crate) fn get_region_cache() -> &'static std::sync::Mutex<std::collections::HashMap<usize, Vec<(usize, usize)>>> {
REGION_CACHE.get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()))
}
pub fn get_valid_memory_regions(handle: HANDLE, use_cache: bool) -> Vec<(usize, usize)> {
let handle_key = handle.0 as usize;
if use_cache {
if let Some(cache) = get_region_cache().lock().ok().as_ref() {
if let Some(cached_regions) = cache.get(&handle_key) {
return cached_regions.clone();
}
}
}
let mut regions = Vec::new();
let mut address = 0x10000usize;
let mut mbi = MEMORY_BASIC_INFORMATION::default();
unsafe {
while VirtualQueryEx(
handle,
Some(address as *const _),
&mut mbi,
std::mem::size_of::<MEMORY_BASIC_INFORMATION>(),
) != 0 {
let protect = mbi.Protect;
if mbi.State == windows::Win32::System::Memory::MEM_COMMIT
&& (protect.0 & (windows::Win32::System::Memory::PAGE_READWRITE.0
| windows::Win32::System::Memory::PAGE_EXECUTE_READ.0
| windows::Win32::System::Memory::PAGE_EXECUTE_READWRITE.0)) != 0
&& (protect.0 & windows::Win32::System::Memory::PAGE_GUARD.0) == 0 {
regions.push((mbi.BaseAddress as usize, mbi.RegionSize));
}
address += mbi.RegionSize;
}
}
if use_cache {
if let Ok(mut cache) = get_region_cache().lock() {
cache.insert(handle_key, regions.clone());
}
}
regions
}