win-handles-sys 0.1.1

Memory-safe Rust over the Win32 handle and object API: duplicating a handle with the access kept or chosen and its inheritance chosen, with a typed access mask, and reading and setting a handle's flags, asking whether two handles name one object, and closing a handle with its result. Thin over Win32, adding no policy.
Documentation

win-handles-sys

Memory-safe Rust over the Win32 handle and object API, the area Microsoft Learn files under System Services > Windows System Information > Handles and Objects. Thin over Win32, adding no policy.

  • duplicate_handle is DuplicateHandle over any handle, in this process, with the access either the source's or a mask chosen, and whether a child process can inherit the duplicate chosen. duplicate_handle_with_access is the same call with a mask and no inheritance, and the rest of this bullet is true of both. It returns an OwnedHandle, so the duplicate is closed when it is dropped and nothing else has to.
  • get_handle_information is GetHandleInformation: the HandleFlags a handle carries, whether it is inheritable and whether closing it is refused. A bit Windows defines that is not named is kept, not refused.
  • set_handle_information is SetHandleInformation: the same HandleFlags, with a mask of which are changed. A flag in the mask is set if the flags have it and cleared if they do not, and one outside the mask is left as it was. Nothing is refused before the call. A handle protected from close is not closed by dropping it, so clear the flag first.
  • compare_object_handles is CompareObjectHandles: whether two handles name the same kernel object, which needs no access right on either. It returns the call's TRUE or FALSE as a bool. A duplicate is the same object; two opens of one file are not. It needs Windows 10 or Windows Server 2016.
  • close_handle is CloseHandle over an OwnedHandle: what dropping one does, with the result kept, for a caller that needs to know the close worked. The handle is taken whether or not it succeeds and is not given back; one protected from close fails to close and stays open, so clear the flag first.
  • Access is the mask, a newtype over the Win32 bits combined with |. SYNCHRONIZE and EVENT_MODIFY_STATE are named; any other right is Access::from_bits.

Windows does not confine a duplicate to the source handle's access. A duplicate may ask for rights the source lacks and get them, so narrowing is a guard against a handle being used for what it was not handed out for, and not a boundary against code in the process that sets out to cross it.

use std::fs::File;

use win_handles_sys::{Access, duplicate_handle_with_access};

let path = std::env::temp_dir().join(format!("wh-doc-{}.tmp", std::process::id()));
let file = File::create(&path)?;

// A second handle to the same file, that can wait on it and do nothing else.
let waiter = duplicate_handle_with_access(&file, Access::SYNCHRONIZE)?;
drop(waiter);
# drop(file);
# std::fs::remove_file(&path)?;
# Ok::<(), std::io::Error>(())

A duplicate that keeps the source's access, and that a child process can inherit:

use std::fs::File;

use win_handles_sys::{DuplicateAccess, Inheritance, duplicate_handle};

let path = std::env::temp_dir().join(format!("wh-doc-inherit-{}.tmp", std::process::id()));
let file = File::create(&path)?;

let for_a_child = duplicate_handle(&file, DuplicateAccess::Same, Inheritance::Inheritable)?;
drop(for_a_child);
# drop(file);
# std::fs::remove_file(&path)?;
# Ok::<(), std::io::Error>(())

The crate was made by moving this code out of win-sync-sys. From that crate's release that depends on this one, it re-exports this crate at the paths it had; a release from before then has its own copy, whose types are distinct from these.