1 use core::{mem, ptr};
2
3 use winapi::ctypes::c_void;
4
5 use crate::SysResult;
6
7 const GHND: winapi::ctypes::c_uint = 0x42;
8
9 const BYTES_LAYOUT: alloc::alloc::Layout = alloc::alloc::Layout::new::<u8>();
10
11 #[inline]
noop(_: *mut c_void)12 fn noop(_: *mut c_void) {
13 }
14
15 #[inline]
free_rust_mem(data: *mut c_void)16 fn free_rust_mem(data: *mut c_void) {
17 unsafe {
18 alloc::alloc::dealloc(data as _, BYTES_LAYOUT)
19 }
20 }
21
22 #[inline]
unlock_data(data: *mut c_void)23 fn unlock_data(data: *mut c_void) {
24 unsafe {
25 winapi::um::winbase::GlobalUnlock(data);
26 }
27 }
28
29 #[inline]
free_global_mem(data: *mut c_void)30 fn free_global_mem(data: *mut c_void) {
31 unsafe {
32 winapi::um::winbase::GlobalFree(data);
33 }
34 }
35
36 pub struct Scope<T: Copy>(pub T, pub fn(T));
37
38 impl<T: Copy> Drop for Scope<T> {
39 #[inline(always)]
drop(&mut self)40 fn drop(&mut self) {
41 (self.1)(self.0)
42 }
43 }
44
45 pub struct RawMem(Scope<*mut c_void>);
46
47 impl RawMem {
48 #[inline(always)]
new_rust_mem(size: usize) -> Self49 pub fn new_rust_mem(size: usize) -> Self {
50 let mem = unsafe {
51 alloc::alloc::alloc_zeroed(alloc::alloc::Layout::array::<u8>(size).expect("To create layout for bytes"))
52 };
53 debug_assert!(!mem.is_null());
54 Self(Scope(mem as _, free_rust_mem))
55 }
56
57 #[inline(always)]
new_global_mem(size: usize) -> SysResult<Self>58 pub fn new_global_mem(size: usize) -> SysResult<Self> {
59 unsafe {
60 let mem = winapi::um::winbase::GlobalAlloc(GHND, size as _);
61 if mem.is_null() {
62 Err(error_code::SystemError::last())
63 } else {
64 Ok(Self(Scope(mem, free_global_mem)))
65 }
66 }
67 }
68
69 #[inline(always)]
from_borrowed(ptr: ptr::NonNull<c_void>) -> Self70 pub fn from_borrowed(ptr: ptr::NonNull<c_void>) -> Self {
71 Self(Scope(ptr.as_ptr(), noop))
72 }
73
74 #[inline(always)]
get(&self) -> *mut c_void75 pub fn get(&self) -> *mut c_void {
76 (self.0).0
77 }
78
79 #[inline(always)]
release(self)80 pub fn release(self) {
81 mem::forget(self)
82 }
83
lock(&self) -> SysResult<(ptr::NonNull<c_void>, Scope<*mut c_void>)>84 pub fn lock(&self) -> SysResult<(ptr::NonNull<c_void>, Scope<*mut c_void>)> {
85 let ptr = unsafe {
86 winapi::um::winbase::GlobalLock(self.get())
87 };
88
89 match ptr::NonNull::new(ptr) {
90 Some(ptr) => Ok((ptr, Scope(self.get(), unlock_data))),
91 None => Err(error_code::SystemError::last()),
92 }
93 }
94 }
95