winsafe 0.0.27

Windows API and GUI in safe, idiomatic Rust.
Documentation
use std::ops::Deref;

use crate::co;
use crate::decl::*;
use crate::kernel::privs::*;
use crate::ole::ffi;
use crate::prelude::*;

/// RAII implementation which automatically calls
/// [`CoLockObjectExternal`](https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-colockobjectexternal)
/// to unlock the COM pointer.
pub struct CoLockObjectExternalGuard<'a, T>
where
	T: ole_IUnknown,
{
	com_obj: &'a T,
}

impl<'a, T> Drop for CoLockObjectExternalGuard<'a, T>
where
	T: ole_IUnknown,
{
	fn drop(&mut self) {
		unsafe {
			ffi::CoLockObjectExternal(self.com_obj.ptr(), 0, 1); // ignore errors
		}
	}
}

impl<'a, T> CoLockObjectExternalGuard<'a, T>
where
	T: ole_IUnknown,
{
	/// Constructs the guard by keeping the reference to the COM pointer.
	///
	/// # Safety
	///
	/// Be sure the COM pointer has been locked with a previous call to
	/// [`CoLockObjectExternal`](https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-colockobjectexternal).
	#[must_use]
	pub const unsafe fn new(com_obj: &'a T) -> Self {
		Self { com_obj }
	}
}

/// RAII implementation which automatically calls
/// [`CoTaskMemFree`](https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-cotaskmemfree)
/// when the object goes out of scope.
pub struct CoTaskMemFreeGuard {
	pmem: *mut std::ffi::c_void,
	sz: usize,
}

impl Drop for CoTaskMemFreeGuard {
	fn drop(&mut self) {
		if !self.pmem.is_null() {
			unsafe {
				ffi::CoTaskMemFree(self.pmem);
			}
		}
	}
}

impl CoTaskMemFreeGuard {
	/// Constructs the guard.
	///
	/// # Safety
	///
	/// Be sure the pointer must be freed with
	/// [`CoTaskMemFree`](https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-cotaskmemfree)
	/// at the end of the scope, and the size is correct.
	#[must_use]
	pub const unsafe fn new(pmem: *mut std::ffi::c_void, sz: usize) -> Self {
		Self { pmem, sz }
	}

	/// Ejects the underlying memory pointer and size, leaving null and zero in
	/// their places.
	///
	/// Since the internal memory pointer will be invalidated, the destructor
	/// will not run. It's your responsibility to run it, otherwise you'll cause
	/// a memory leak.
	#[must_use]
	pub fn leak(&mut self) -> (*mut std::ffi::c_void, usize) {
		(
			std::mem::replace(&mut self.pmem, std::ptr::null_mut()),
			std::mem::replace(&mut self.sz, 0),
		)
	}

	pub_fn_mem_block!();
}

/// RAII implementation which automatically calls
/// [`CoUninitialize`](https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-couninitialize)
/// when the object goes out of scope.
pub struct CoUninitializeGuard {
	hr: co::HRESULT,
}

impl Drop for CoUninitializeGuard {
	fn drop(&mut self) {
		unsafe {
			ffi::CoUninitialize();
		}
	}
}

impl CoUninitializeGuard {
	/// Constructs the guard by taking ownership of the code.
	///
	/// # Safety
	///
	/// Be sure you need to call
	/// [`CoUninitialize`](https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-couninitialize)
	/// at the end of scope.
	#[must_use]
	pub const unsafe fn new(hr: co::HRESULT) -> Self {
		Self { hr }
	}

	/// Returns the informational success code returned by
	/// [`CoInitializeEx`](crate::CoInitializeEx).
	#[must_use]
	pub const fn hr(&self) -> co::HRESULT {
		self.hr
	}
}

/// RAII implementation which automatically calls
/// [`OleUninitialize`](https://learn.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-oleuninitialize)
/// when the object goes out of scope.
///
/// Returned by [`OleInitialize`](crate::OleInitialize).
pub struct OleUninitializeGuard {}

impl Drop for OleUninitializeGuard {
	fn drop(&mut self) {
		unsafe {
			ffi::OleUninitialize();
		}
	}
}

impl OleUninitializeGuard {
	/// Constructs the guard.
	///
	/// # Safety
	///
	/// Be sure you need to call
	/// [`OleUninitialize`](https://learn.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-oleuninitialize)
	/// at the end of scope.
	#[must_use]
	pub const unsafe fn new() -> Self {
		Self {}
	}
}

/// RAII implementation which automatically calls
/// [`ReleaseStgMedium`](https://learn.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-releasestgmedium)
/// when the object goes out of scope.
pub struct ReleaseStgMediumGuard {
	stgm: STGMEDIUM,
}

impl Drop for ReleaseStgMediumGuard {
	fn drop(&mut self) {
		unsafe {
			ffi::ReleaseStgMedium(pvoid(&mut self.stgm));
		}
	}
}

impl Deref for ReleaseStgMediumGuard {
	type Target = STGMEDIUM;

	fn deref(&self) -> &Self::Target {
		&self.stgm
	}
}

impl ReleaseStgMediumGuard {
	/// Constructs the guard by taking ownership of the struct.
	///
	/// # Safety
	///
	/// Be sure you need to call
	/// [`ReleaseStgMedium`](https://learn.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-releasestgmedium)
	/// at the end of the scope.
	#[must_use]
	pub const unsafe fn new(stgm: STGMEDIUM) -> Self {
		Self { stgm }
	}
}