I'm trying to call LockFileEx
on a std::fs:File
and struggle since type HANDLE
has multiple implementations:
windows::Win32::Foundation::HANDLE
std::os::windows::io::BorrowedHandle
std::os::windows::raw::HANDLE
My current attempt is as follows:
fn unsafe lock(file: &mut File) -> BOOL {
let mut overlapped = std::mem::zeroed();
LockFileEx(
file.as_handle(),
LOCKFILE_EXCLUSIVE_LOCK,
0,
!0,
!0
&mut overlapped)
}
This fails with
the trait `From<BorrowedHandler<'_>>` is not implemented for `HANDLE`
I'm kind of puzzled because of the different HANDLE
types and was wondering how to make them fit together.
A HANDLE
in Windows is a moniker that identifies a kernel object. Its native type is void*
with its value carrying no inherent meaning. Its sole purpose is to refer that object in communication with the OS, and any library (such as Rust's Standard Library) that needs to interact with the OS will provide a way to represent HANDLE
values.
At the ABI, where rubber meets the road, all libraries (necessarily have to) agree on a specific data type (or at least a type that's binary layout-compatible), yet Rust's type system leaves a lot of headroom to encode circumstantial information:
std::os::windows::raw::HANDLE
is the low-level, ABI-compatible type alias. It's literally just a *mut c_void
, Rust's way of expressing C's void*
.std::os::windows::io::BorrowedHandle
is a #[repr(transparent)]
type over the aforementioned HANDLE
type with lifetime annotations. It is valid for as long as the referenced File
is.windows::Win32::Foundation::HANDLE
is very similar to std::od::windows::raw::HANDLE
in that it transparently wraps a void*
, but stores it as an isize
instead.While it has been discussed whether windows
's HANDLE
should follow the route of lifetime-annotated BorrowedHandle
's this has not been implemented (as of 0.39.0). At this time, the easiest solution would be to just pull out an as_raw_handle()
and feed that into a HANDLE
, e.g.:
unsafe fn lock(file: &mut File) -> BOOL {
let mut overlapped = Default::default();
LockFileEx(
HANDLE(file.as_raw_handle() as isize),
LOCKFILE_EXCLUSIVE_LOCK,
0,
!0,
!0,
&mut overlapped,
)
}
As for the specific error diagnostic, the function signature of LockFileEx
is:
pub unsafe fn LockFileEx<'a, P0>(
hfile: P0,
dwflags: LOCK_FILE_FLAGS,
dwreserved: u32,
nnumberofbytestolocklow: u32,
nnumberofbytestolockhigh: u32,
lpoverlapped: *mut OVERLAPPED
) -> BOOL where
P0: Into<HANDLE>,
rustc
is attempting to invoke an Into
(or From
) trait implementation on the hfile
argument, but cannot find one that matches. This is because it doesn't exist, not just because the caller failed to use
the specific trait implementation.