1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
//! Basic elements of windows (there's a few modules like this really). use super::*; use winapi::um::{ minwinbase::{LHND, LMEM_FIXED, LMEM_INVALID_HANDLE, LMEM_MOVEABLE, LPTR}, winbase::{ LocalAlloc, LocalFlags, LocalFree, LocalHandle, LocalLock, LocalReAlloc, LocalSize, LocalUnlock, }, }; /// The flags that can be used with [`local_alloc`](local_alloc) #[derive(Debug, Clone, Copy)] #[repr(u32)] pub enum LocalAllocFlags { /// Allocates fixed memory. /// /// The return value is a pointer to the memory object. Fixed = LMEM_FIXED, /// As `Fixed` but the memory is zeroed. ZeroedFixed = LPTR, /// Allocates movable memory. Higher overhead, avoid if possible. /// /// Memory blocks are never moved in physical memory, but they can be moved /// within the default heap. The return value is a handle to the memory /// object. To translate the handle to a pointer, use the `LocalLock` /// function. Movable = LMEM_MOVEABLE, /// As `Movable` but the memory is zeroed. ZeroedMovable = LHND, } impl Default for LocalAllocFlags { fn default() -> Self { LocalAllocFlags::Fixed } } /// Allocates bytes from the heap. High overhead. /// /// Avoid this function unless it is documented that you must use it in /// connection with some other function. Use the [heap /// functions](https://docs.microsoft.com/en-us/windows/win32/memory/heap-functions) /// instead. /// /// See /// [`LocalAlloc`](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localalloc) pub unsafe fn local_alloc( flags: LocalAllocFlags, bytes: usize, ) -> Result<HLOCAL, ErrorCode> { let handle = LocalAlloc(flags as u32, bytes); if !handle.is_null() { Ok(handle) } else { Err(get_last_error()) } } /// Changes the size or the attributes of a specified local memory object. /// /// I don't at all understand how this works in practice. /// /// If this function fails the old handle and pointer are still valid. /// /// See /// [`LocalReAlloc`](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localrealloc) #[inline] pub unsafe fn local_realloc( handle: HLOCAL, size: usize, flags: u32, ) -> Result<HLOCAL, ErrorCode> { let output = LocalReAlloc(handle, size, flags); if !output.is_null() { Ok(output) } else { Err(get_last_error()) } } /// Frees/invalidates a Local memory handle. /// /// If you try to free a null handle it's ignored and you get `Ok(())`. /// /// This will free a handle even if it's locked. /// /// See /// [`LocalFree`](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree) #[inline] pub unsafe fn local_free(handle: HLOCAL) -> Result<(), ErrorCode> { let output = LocalFree(handle); if output.is_null() { Ok(()) } else { Err(get_last_error()) } } /// Locks a local handle and gets the address to its actual memory. /// /// * Fixed memory permanently has a lock count of zero, and doesn't need to be /// locked to be used. The `HLOCAL` value can be used directly as the pointer /// to the memory, or you can use this function. /// * Movable memory must be locked to be used, and you **must not** use the /// `HLOCAL` value directly as a pointer. /// /// See /// [`LocalLock`](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-locallock) #[inline] pub unsafe fn local_lock(handle: HLOCAL) -> Result<*mut c_void, ErrorCode> { let output = LocalLock(handle) as *mut c_void; if !output.is_null() { Ok(output) } else { Err(get_last_error()) } } /// Unlocks a local handle. /// /// Returns `Ok(still_locked)` on success. /// /// * Fixed memory permanently has a lock count of zero and will always report /// `ERROR_NOT_LOCKED` if you try to unlock it. /// * Movable memory will report `ERROR_NOT_LOCKED` if it's not currently /// locked. /// /// See /// [`LocalUnlock`](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localunlock) #[inline] pub unsafe fn local_unlock(handle: HLOCAL) -> Result<bool, ErrorCode> { let output = LocalUnlock(handle); if output != 0 { Ok(true) } else { let e = get_last_error(); if e.0 == NO_ERROR { Ok(false) } else { Err(e) } } } /// Flag info about this local handle. /// /// * The low-order byte of the low-order word of the return value contains the /// lock count of the object. /// * The high-order byte of the low-order word of the return value indicates /// the allocation values of the memory object. It can be zero or /// LMEM_DISCARDABLE. /// /// See /// [`LocalFlags`](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localflags) #[inline] pub unsafe fn local_flags(handle: HLOCAL) -> Result<u32, ErrorCode> { let output = LocalFlags(handle); if output != LMEM_INVALID_HANDLE { Ok(output) } else { Err(get_last_error()) } } /// Checks the size of the allocation for this local handle. /// /// The allocation of a local handle can be larger than was requested. /// /// To verify that the allocation hasn't been discarded use /// [`local_flags`](local_flags) **before** calling this function. /// /// See /// [`LocalSize`](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localsize) #[inline] pub unsafe fn local_size(handle: HLOCAL) -> Result<usize, ErrorCode> { let output = LocalSize(handle); if output != 0 { Ok(output) } else { Err(get_last_error()) } } /// Gets the local handle associated with the specified pointer to a local /// memory object. /// /// This is primarily for use with Movable memory, because in that case the /// handle value and the pointer value are not the same. /// /// See /// [`LocalHandle`](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localhandle) #[inline] pub unsafe fn local_handle(ptr: *mut c_void) -> Result<HLOCAL, ErrorCode> { let output = LocalHandle(ptr as *mut _); if !output.is_null() { Ok(output) } else { Err(get_last_error()) } } /// An owning local memory handle wrapper that will free the memory when dropped. #[derive(Debug)] pub(crate) struct OwnedLocalHandle(HLOCAL); #[allow(dead_code)] impl OwnedLocalHandle { /// Wraps the handle given to be an owned value. /// /// ## Safety /// /// Once you have wrapped the `HLOCAL`, you should not attempt to free it /// yourself. You also must not use it after you have dropped this struct. The /// `Drop` code will free the handle for you when this struct drops. pub const unsafe fn new(handle: HLOCAL) -> Self { Self(handle) } /// Copies out the `HLOCAL` value, but it's still owned. /// /// ## Safety /// /// There's no lifetime on this output value, so you must not use it after /// this struct drops. pub const unsafe fn as_hlocal(&self) -> HLOCAL { self.0 } /// Unwraps the `HLOCAL` so that it's no longer owned. pub fn into_inner(self) -> HLOCAL { let out = self.0; core::mem::forget(self); out } } impl Drop for OwnedLocalHandle { fn drop(&mut self) { let free_result = unsafe { local_free(self.0) }; if cfg!(debug_assertions) { free_result.unwrap(); } else { free_result.ok(); }; } } pub(crate) struct FixedLocalSlice<T> { handle: OwnedLocalHandle, data_type: PhantomData<T>, count: usize, } impl<T> FixedLocalSlice<T> { /// ## Safety /// /// ONLY ALLOWED FOR FIXED MEMORY pub const unsafe fn new(handle: OwnedLocalHandle, count: usize) -> Self { Self { handle, count, data_type: PhantomData, } } } impl<T> Deref for FixedLocalSlice<T> { type Target = [T]; fn deref(&self) -> &[T] { unsafe { core::slice::from_raw_parts(self.handle.0 as *const T, self.count) } } }