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
#![allow(non_snake_case)]

use crate::aliases::WinResult;
use crate::co;
use crate::ffi::kernel32;
use crate::funcs::{GetLastError, HIDWORD, LODWORD};
use crate::privs::bool_to_winresult;

pub_struct_handle_closeable! {
	/// Handle to a
	/// [file mapping](https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw).
	/// Originally just a `HANDLE`.
	HFILEMAP
}

impl HFILEMAP {
	/// [`MapViewOfFile`](https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile)
	/// method.
	///
	/// **Note:** Must be paired with an
	/// [`HFILEMAPVIEW::UnmapViewOfFile`](crate::HFILEMAPVIEW::UnmapViewOfFile)
	/// call.
	pub fn MapViewOfFile(self,
		desired_access: co::FILE_MAP,
		offset: u64,
		number_of_bytes_to_map: Option<i64>) -> WinResult<HFILEMAPVIEW>
	{
		unsafe {
			kernel32::MapViewOfFile(
				self.ptr,
				desired_access.0,
				HIDWORD(offset),
				LODWORD(offset),
				number_of_bytes_to_map.unwrap_or_default(),
			).as_mut()
		}.map(|ptr| HFILEMAPVIEW { ptr })
			.ok_or_else(|| GetLastError())
	}
}

//------------------------------------------------------------------------------

pub_struct_handle! {
	/// Address of a
	/// [mapped view](https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile).
	/// Originally just an `LPVOID`.
	HFILEMAPVIEW
}

impl HFILEMAPVIEW {
	/// [`UnmapViewOfFile`](https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-unmapviewoffile)
	/// method.
	pub fn UnmapViewOfFile(self) -> WinResult<()> {
		bool_to_winresult(unsafe { kernel32::UnmapViewOfFile(self.ptr) })
	}

	/// Returns a slice representing the mapped memory. You can modify the
	/// contents. You should call this method only if the file has write access.
	///
	/// **Note**: If the file is resized to a smaller size, the slice will still
	/// map the bytes beyond the file. This may cause serious errors. So, if the
	/// file is resized, re-generate the slice by calling `as_slice` again.
	pub fn as_mut_slice<'a>(self, len: usize) -> &'a mut [u8] {
		unsafe { std::slice::from_raw_parts_mut(self.ptr as _, len) }
	}

	/// Returns a slice representing the mapped memory.
	///
	/// **Note**: If the file is resized to a smaller size, the slice will still
	/// map the bytes beyond the file. This may cause serious errors. So, if the
	/// file is resized, re-generate the slice by calling `as_slice` again.
	///
	/// # Examples
	///
	/// Reading the contents of a file into a string:
	///
	/// ```rust,ignore
	/// use winsafe::{co, HFILE};
	///
	/// let hfile = HFILE::CreateFile(
	///     "C:\\Temp\\test.txt",
	///     co::GENERIC::READ,
	///     co::FILE_SHARE::READ,
	///     None,
	///     co::DISPOSITION::OPEN_EXISTING,
	///     co::FILE_ATTRIBUTE::NORMAL,
	///     None,
	/// )?;
	///
	/// let hmap = hfile.CreateFileMapping(
	///     None,
	///     co::PAGE::READONLY,
	///     None,
	///     None,
	/// )?;
	///
	/// let view = hmap.MapViewOfFile(co::FILE_MAP::READ, 0, None)?;
	///
	/// let slice = view.as_slice(hfile.GetFileSizeEx()?);
	/// let text = std::str::from_utf8(slice)?;
	///
	/// view.UnmapViewOfFile()?;
	/// hmap.CloseHandle()?;
	/// hfile.CloseHandle()?;
	///
	/// println!("{}", text);
	/// ```
	pub fn as_slice<'a>(self, len: usize) -> &'a [u8] {
		unsafe { std::slice::from_raw_parts(self.ptr as _, len) }
	}
}