Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds unsafe helpers to cast from C++ or raw IUnknown pointers to Rust IUnknown values #2010

Merged
merged 4 commits into from Sep 8, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions crates/libs/windows/src/core/interface.rs
Expand Up @@ -48,6 +48,26 @@ pub unsafe trait Interface: Sized {
raw
}

/// Creates an `Interface` by taking ownership of the `raw` COM interface pointer.
///
/// # Safety
///
/// The `raw` pointer must be owned by the caller and represent a valid COM interface pointer. In other words,
/// it must point to a vtable beginning with the `IUnknown` function pointers and match the vtable of `Interface`.
unsafe fn from_raw(raw: *mut core::ffi::c_void) -> Self {
std::mem::transmute_copy(&raw)
}

/// Creates an `Interface` that is valid so long as the `raw` COM interface pointer is valid.
///
/// # Safety
///
/// The `raw` pointer must be a valid COM interface pointer. In other words, it must point to a vtable
/// beginning with the `IUnknown` function pointers and match the vtable of `Interface`.
unsafe fn from_raw_borrowed<'a>(raw: &'a *mut core::ffi::c_void) -> &'a Self {
std::mem::transmute_copy(&raw)
}

/// Attempts to create a [`Weak`] reference to this object.
fn downgrade(&self) -> Result<Weak<Self>> {
self.cast::<IWeakReferenceSource>().and_then(|source| Weak::downgrade(&source))
Expand Down
22 changes: 0 additions & 22 deletions crates/libs/windows/src/core/unknown.rs
Expand Up @@ -7,28 +7,6 @@ use super::*;
#[repr(transparent)]
pub struct IUnknown(core::ptr::NonNull<core::ffi::c_void>);

impl IUnknown {
/// Creates an `IUnknown` value by taking ownership of the `raw` COM interface pointer.
///
/// # Safety
///
/// The `raw` pointer must be owned by the caller and represent a valid COM interface pointer. In other words,
/// it must point to a vtable beginning with the `IUnknown` function pointers.
pub unsafe fn from_raw(raw: *mut core::ffi::c_void) -> Self {
std::mem::transmute(raw)
}

/// Creates a borrowed `IUnknown` that is valid so long as the `raw` COM interface pointer is valid.
///
/// # Safety
///
/// The `raw` pointer must be a valid COM interface pointer. In other words, it must point to a vtable
/// beginning with the `IUnknown` function pointers.
pub unsafe fn from_raw_borrowed<'a>(raw: &'a *mut core::ffi::c_void) -> &'a Self {
std::mem::transmute(raw)
}
}

#[doc(hidden)]
#[repr(C)]
pub struct IUnknownVtbl {
Expand Down
27 changes: 26 additions & 1 deletion crates/tests/core/tests/unknown.rs
Expand Up @@ -27,7 +27,7 @@ impl Drop for Test {
}

#[test]
fn test() {
fn test_unknown() {
unsafe {
let mut dropped = 0;
let test: ITest = Test { drop: &mut dropped }.into();
Expand All @@ -52,3 +52,28 @@ fn test() {
assert_eq!(dropped, 1);
}
}

#[test]
fn test_test() {
kennykerr marked this conversation as resolved.
Show resolved Hide resolved
unsafe {
let mut dropped = 0;
let test: ITest = Test { drop: &mut dropped }.into();

{
let raw_borrowed: *mut std::ffi::c_void = test.as_raw();
let test_borrowed: &ITest = ITest::from_raw_borrowed(&raw_borrowed);
assert_eq!(test_borrowed.as_raw(), test.as_raw());
assert_eq!(test_borrowed.Test(), 0);
}
{
let raw_owned: *mut std::ffi::c_void = test.clone().into_raw();
let unknown_owned: ITest = ITest::from_raw(raw_owned);
assert_eq!(unknown_owned.as_raw(), test.as_raw());
assert_eq!(unknown_owned.Test(), 0);
}

assert_eq!(test.Test(), 0);
drop(test);
assert_eq!(dropped, 1);
}
}