1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use std::ffi::c_void;
use std::fmt;
use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr::NonNull;
use crate::{HResult, Interface, E_NOINTERFACE, S_OK};
/// Owning, non-null COM interface pointer: holds exactly one reference.
///
/// Not `Send`/`Sync`: the native objects are UI-thread affine.
#[repr(transparent)]
pub struct ComPtr<T: Interface> {
ptr: NonNull<T>,
_marker: PhantomData<*mut T>,
}
impl<T: Interface> ComPtr<T> {
/// Takes ownership of one existing reference (no `AddRef`). Returns
/// `None` for null.
///
/// # Safety
/// `raw` must be null or a valid pointer to a COM object implementing `T`
/// whose reference the caller owns.
#[inline]
pub unsafe fn from_raw(raw: *mut T) -> Option<Self> {
NonNull::new(raw).map(|ptr| ComPtr { ptr, _marker: PhantomData })
}
/// `AddRef`s a borrowed pointer and wraps it. Returns `None` for null.
///
/// # Safety
/// `raw` must be null or a valid pointer to a COM object implementing `T`.
#[inline]
pub unsafe fn from_raw_add_ref(raw: *mut T) -> Option<Self> {
let p = Self::from_raw(raw)?;
p.as_unknown().add_ref();
Some(p)
}
/// `AddRef`s a borrowed interface reference.
#[inline]
pub fn from_ref(r: &T) -> Self {
// SAFETY: `&T` always refers to a live COM object.
unsafe { Self::from_raw_add_ref(r.as_raw()).unwrap_unchecked() }
}
/// Borrowed raw pointer; the reference count is unchanged.
#[inline]
pub fn as_ptr(&self) -> *mut T {
self.ptr.as_ptr()
}
/// Gives up ownership without releasing.
#[inline]
pub fn into_raw(self) -> *mut T {
let p = self.ptr.as_ptr();
std::mem::forget(self);
p
}
/// `QueryInterface` for `U`.
///
/// The native library compares against the IIDs materialized by `com.h`
/// (see [`crate::Guid::as_com_h_materialized`]), Rust-implemented objects
/// accept both forms; so the materialized form is tried first and the IDL
/// form second.
pub fn cast<U: Interface>(&self) -> Result<ComPtr<U>, HResult> {
let mut last = E_NOINTERFACE;
for iid in [U::IID.as_com_h_materialized(), U::IID] {
let mut out: *mut c_void = std::ptr::null_mut();
// SAFETY: valid object, valid out pointer.
let hr = unsafe { self.as_unknown().query_interface_raw(&iid, &mut out) };
if hr == S_OK {
// SAFETY: QueryInterface returned an owned reference to `U`.
return unsafe { ComPtr::from_raw(out as *mut U) }.ok_or(HResult::POINTER);
}
last = hr;
}
Err(HResult(last))
}
}
impl<T: Interface> Deref for ComPtr<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
// SAFETY: we hold a reference, so the object is alive.
unsafe { self.ptr.as_ref() }
}
}
impl<T: Interface> Clone for ComPtr<T> {
#[inline]
fn clone(&self) -> Self {
// SAFETY: the object is alive.
unsafe { self.as_unknown().add_ref() };
ComPtr { ptr: self.ptr, _marker: PhantomData }
}
}
impl<T: Interface> Drop for ComPtr<T> {
#[inline]
fn drop(&mut self) {
// SAFETY: we own one reference.
unsafe { self.as_unknown().release() };
}
}
impl<T: Interface> PartialEq for ComPtr<T> {
fn eq(&self, other: &Self) -> bool {
self.ptr == other.ptr
}
}
impl<T: Interface> fmt::Debug for ComPtr<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ComPtr<{}>({:p})", T::NAME, self.ptr.as_ptr())
}
}