Skip to content

Commit 0dfa3de

Browse files
contextfreeBoddlnagg
authored andcommitted
Provide COM_INTERFACE macro to support COM interop; export dependencies
The implementation of the macro mostly closely mirrors RT_INTERFACE!; I started with a copy of that macro, removed support for WinRT-specific features (generics, statics, IInspectable special case) and Rt* trait impls, then added the method impls directly in the macro expansion since we can't rely on generated code here. The other major difference for the user is that those method impls are all marked unsafe and expose an unrefined direct translation of the ABI with raw pointers, exposed HRESULTs, out pointers for returns, PascalCasing, etc. The idea is that our COM interop support is intended to be purely a low-level FFI rather than a higher-level "projection," reflecting that projections are mostly a WinRT-specific concept.
1 parent 079a326 commit 0dfa3de

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

src/comptr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl<Vtbl> Clone for ComAbi<Vtbl> {
2929
/// Smart pointer for Windows Runtime objects. This pointer automatically maintains the
3030
/// reference count of the underlying COM object.
3131
#[repr(transparent)]
32-
pub(crate) struct ComPtr<T: ComInterfaceAbi>(ptr::NonNull<T>);
32+
pub struct ComPtr<T: ComInterfaceAbi>(ptr::NonNull<T>);
3333

3434
pub(crate) trait ComPtrHelpers {
3535
/// Changes the type of the underlying COM object to a different interface without doing `QueryInterface`.
@@ -69,7 +69,7 @@ impl<T: ComInterfaceAbi> ComPtr<T> {
6969
}
7070

7171
#[inline]
72-
pub(crate) fn as_abi(&self) -> &T {
72+
pub fn as_abi(&self) -> &T {
7373
unsafe { self.0.as_ref() }
7474
}
7575
}

src/interop.rs

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#[allow(unused_macros)]
2+
#[macro_export]
3+
macro_rules! COM_INTERFACE {
4+
// version with no methods
5+
($(#[$attr:meta])* interface $interface:ident ($vtbl:ident) : $pinterface:ident [$iid:ident]
6+
{}
7+
) => {
8+
#[repr(transparent)] #[allow(missing_copy_implementations)] #[doc(hidden)]
9+
pub struct $vtbl {
10+
pub parent: <<$pinterface as $crate::ComInterface>::TAbi as $crate::ComInterfaceAbi>::Vtbl
11+
}
12+
$(#[$attr])* #[repr(transparent)] #[derive(Clone)]
13+
pub struct $interface($crate::ComPtr<$crate::ComAbi<$vtbl>>);
14+
impl $crate::ComIid for $interface {
15+
#[inline] fn iid() -> &'static crate::Guid { &$iid }
16+
}
17+
impl $crate::ComInterface for $interface {
18+
type TAbi = $crate::ComAbi<$vtbl>;
19+
#[inline] unsafe fn wrap_com(ptr: *mut Self::TAbi) -> Self { $interface($crate::ComPtr::wrap(ptr)) }
20+
#[inline] fn get_abi(&self) -> &Self::TAbi { self.0.as_abi() }
21+
}
22+
impl std::ops::Deref for $interface {
23+
type Target = $crate::$pinterface;
24+
#[inline]
25+
fn deref(&self) -> &$crate::$pinterface {
26+
unsafe { std::mem::transmute(self) }
27+
}
28+
}
29+
impl std::ops::DerefMut for $interface {
30+
#[inline]
31+
fn deref_mut(&mut self) -> &mut $crate::$pinterface {
32+
unsafe { std::mem::transmute(self) }
33+
}
34+
}
35+
};
36+
37+
// version with methods
38+
($(#[$attr:meta])* interface $interface:ident ($vtbl:ident) : $pinterface:ident [$iid:ident]
39+
{$(
40+
$(#[cfg($cond_attr:meta)])* fn $method:ident(&mut self $(,$p:ident : $t:ty)*) -> $rtr:ty
41+
),+}
42+
) => {
43+
#[repr(C)] #[allow(missing_copy_implementations)] #[doc(hidden)]
44+
pub struct $vtbl {
45+
pub parent: <<$pinterface as $crate::ComInterface>::TAbi as $crate::ComInterfaceAbi>::Vtbl
46+
$(, $(#[cfg($cond_attr)])* pub $method: unsafe extern "system" fn(
47+
This: *mut $interface
48+
$(,$p: $t)*
49+
) -> $rtr)+
50+
}
51+
$(#[$attr])* #[repr(transparent)] #[derive(Clone)]
52+
pub struct $interface($crate::ComPtr<$crate::ComAbi<$vtbl>>);
53+
impl $interface {
54+
#[inline]
55+
$(pub unsafe fn $method(&mut self $(,$p: $t)*) -> $rtr {
56+
let abi = $crate::ComInterface::get_abi(&*self);
57+
((*$crate::ComInterfaceAbi::get_vtbl(&*abi)).$method)(
58+
abi as *const _ as *mut _ $(,$p)*
59+
)
60+
})+
61+
}
62+
impl $crate::ComIid for $interface {
63+
#[inline] fn iid() -> &'static crate::Guid { &$iid }
64+
}
65+
impl $crate::ComInterface for $interface {
66+
type TAbi = $crate::ComAbi<$vtbl>;
67+
#[inline] unsafe fn wrap_com(ptr: *mut Self::TAbi) -> Self { $interface($crate::ComPtr::wrap(ptr)) }
68+
#[inline] fn get_abi(&self) -> &Self::TAbi { self.0.as_abi() }
69+
}
70+
impl std::ops::Deref for $interface {
71+
type Target = $crate::$pinterface;
72+
#[inline]
73+
fn deref(&self) -> &$crate::$pinterface {
74+
unsafe { std::mem::transmute(self) }
75+
}
76+
}
77+
impl std::ops::DerefMut for $interface {
78+
#[inline]
79+
fn deref_mut(&mut self) -> &mut $crate::$pinterface {
80+
unsafe { std::mem::transmute(self) }
81+
}
82+
}
83+
};
84+
}

src/lib.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub use guid::Guid;
3737
pub type TrustLevel = w::winrt::inspectable::TrustLevel;
3838

3939
// Compared to the DEFINE_GUID macro from winapi, this one creates a private const
40+
#[macro_export]
4041
macro_rules! DEFINE_IID {
4142
(
4243
$name:ident, $l:expr, $w1:expr, $w2:expr, $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr,
@@ -57,12 +58,13 @@ mod bstr;
5758
pub use bstr::BStr;
5859

5960
mod comptr;
60-
pub(crate) use comptr::ComPtr;
61-
pub use comptr::ComArray;
61+
pub use comptr::{ComPtr, ComArray, ComAbi};
6262

6363
mod cominterfaces;
6464
pub use cominterfaces::{ComInterface, ComInterfaceAbi, ComIid, IUnknown, IRestrictedErrorInfo, IAgileObject};
6565

66+
pub mod interop;
67+
6668
mod rt;
6769
pub use rt::{RtInterface, RtClassInterface, RtNamedClass, RtValueType, RtType, RtActivatable,
6870
RtDefaultConstructible, IInspectable, IInspectableVtbl, IActivationFactory,

0 commit comments

Comments
 (0)