use std::ops::{Deref, DerefMut};
use windows::Win32::Foundation::{CloseHandle, LocalFree, HANDLE, HLOCAL};
use windows::Win32::Security::Cryptography::{
NCryptFreeBuffer, NCryptFreeObject, NCryptKeyName, NCRYPT_KEY_HANDLE, NCRYPT_PROV_HANDLE,
};
macro_rules! define_raii_handle {
($(#[$meta:meta])* $vis:vis $name:ident($field_vis:vis $handle_type:ty), $cleanup_fn:path, $check:ident) => {
$(#[$meta])*
$vis struct $name($field_vis $handle_type);
impl Drop for $name {
fn drop(&mut self) {
if !self.0.$check() {
unsafe {
let _ = $cleanup_fn(self.0);
}
}
}
}
};
($(#[$meta:meta])* $vis:vis $name:ident($field_vis:vis $handle_type:ty), $cleanup_fn:path, $check:ident, deref) => {
define_raii_handle!($(#[$meta])* $vis $name($field_vis $handle_type), $cleanup_fn, $check);
impl Deref for $name {
type Target = $handle_type;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for $name {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
};
($(#[$meta:meta])* $vis:vis $name:ident($field_vis:vis $handle_type:ty), $cleanup_fn:path, $check:ident, cast: $cast_type:ty) => {
$(#[$meta])*
$vis struct $name($field_vis $handle_type);
impl Drop for $name {
fn drop(&mut self) {
if !self.0.$check() {
unsafe {
let _ = $cleanup_fn(self.0 as $cast_type);
}
}
}
}
};
}
define_raii_handle!(pub HLocalGuard(HLOCAL), LocalFree, is_invalid);
impl HLocalGuard {
pub fn new() -> Self {
Self(HLOCAL::default())
}
pub fn set_from_pwstr(&mut self, pwstr: windows::core::PWSTR) {
self.0 = HLOCAL(pwstr.as_ptr() as *mut _);
}
}
define_raii_handle!(
pub WindowsHandleGuard(pub HANDLE), CloseHandle, is_invalid, deref
);
impl WindowsHandleGuard {
pub fn new() -> Self {
Self(HANDLE::default())
}
}
define_raii_handle!(
pub ProviderHandle(pub NCRYPT_PROV_HANDLE), NCryptFreeObject, is_invalid, deref
);
define_raii_handle!(
pub KeyHandle(pub NCRYPT_KEY_HANDLE), NCryptFreeObject, is_invalid, deref
);
impl KeyHandle {
pub fn take(self) -> NCRYPT_KEY_HANDLE {
let handle = self.0;
std::mem::forget(self);
handle
}
}
define_raii_handle!(
pub EnumStateGuard(*mut std::ffi::c_void), NCryptFreeBuffer, is_null
);
impl EnumStateGuard {
pub fn new() -> Self {
Self(std::ptr::null_mut())
}
pub fn as_mut_ptr(&mut self) -> *mut *mut std::ffi::c_void {
&mut self.0
}
}
define_raii_handle!(
pub KeyNameBufferGuard(*mut NCryptKeyName), NCryptFreeBuffer, is_null, cast: *mut std::ffi::c_void
);
impl KeyNameBufferGuard {
pub fn new(ptr: *mut NCryptKeyName) -> Self {
Self(ptr)
}
pub fn as_ref(&self) -> &NCryptKeyName {
unsafe { &*self.0 }
}
}