com_scrape_types/lib.rs
1//! Support types and traits for bindings generated by `com-scrape`.
2//!
3//! [`ComPtr`] and [`ComRef`] are smart pointers for interacting with COM objects (calling methods,
4//! casting between interfaces, and managing reference counts). The [`Class`] trait can be used for
5//! defining COM classes in Rust, and [`ComWrapper`] is a smart pointer used for instantiating
6//! those classes.
7//!
8//! # Reference counting
9//!
10//! COM objects are reference-counted. The [`ComPtr`] and [`ComRef`] smart pointers manage this
11//! automatically where possible, but the function signatures generated by `com-scrape` still pass
12//! COM objects as raw pointers, and care must be taken to handle issues of ownership correctly
13//! when converting between [`ComPtr`] or [`ComRef`] and raw pointers at these boundaries.
14//!
15//! A thorough overview of how to manage reference counts for COM objects in a variety of situations
16//! can be found on the ["Rules for Managing Reference Counts"][rules] page in the Microsoft COM
17//! documentation, and the documentation for each individual [`ComPtr`] and[`ComRef`] method
18//! specifies its effect on an object's reference count. However, the following rules of thumb
19//! should suffice in the majority of situations:
20//!
21//! 1. When passing an interface pointer as a function parameter, use [`ComPtr::as_ptr`] to obtain a
22//! raw pointer from a [`ComPtr`], or use [`ComRef::as_ptr`] to obtain a raw pointer from a
23//! [`ComRef`].
24//!
25//! 2. When receiving an interface pointer as the return value of a function (or via an out
26//! parameter), always use [`ComPtr::from_raw`] to obtain a [`ComPtr`] from the raw pointer.
27//!
28//! 3. When receiving an interface pointer as a function parameter, always use
29//! [`ComRef::from_raw`] to obtain a [`ComRef`] from the raw pointer. If the received interface
30//! pointer will be stored beyond the duration of the current function, use
31//! [`ComRef::to_com_ptr`] to upgrade the [`ComRef`] to a [`ComPtr`].
32//!
33//! 4. When returning an interface pointer from a function (or when returning it via an out
34//! parameter), always use [`ComPtr::into_raw`] to obtain a raw pointer from a [`ComPtr`].
35//!
36//! [rules]: https://learn.microsoft.com/en-us/windows/win32/com/rules-for-managing-reference-counts
37//!
38//! # Implementing COM interfaces from Rust
39//!
40//! The [`Class`] trait can be used to define COM classes in Rust, and the [`ComWrapper`] smart
41//! pointer can be used to instantiate objects of these classes. To define a COM class, start by
42//! defining a Rust type:
43//!
44//! ```ignore
45//! struct MyClass { /* ... */ }
46//! ```
47//!
48//! Then implement the desired interface traits for the type:
49//!
50//! ```ignore
51//! impl ISomeInterfaceTrait for MyClass {
52//! unsafe fn some_method(&self) {
53//! /* ... */
54//! }
55//! }
56//!
57//! impl IAnotherInterfaceTrait for MyClass {
58//! unsafe fn another_method(&self) {
59//! /* ... */
60//! }
61//! }
62//! ```
63//!
64//! Finally, implement the [`Class`] trait for the type, specifying the set of COM interfaces as a
65//! tuple:
66//!
67//! ```ignore
68//! impl Class for MyClass {
69//! type Interfaces = (ISomeInterface, IAnotherInterface);
70//! }
71//! ```
72//!
73//! With these definitions in place, [`ComWrapper`] can be used to instantiate a COM object
74//! supporting the above interfaces:
75//!
76//! ```ignore
77//! let my_obj = ComWrapper::new(MyClass);
78//!
79//! let ptr = my_obj.to_com_ptr::<ISomeInterface>().unwrap();
80//! ptr.some_method();
81//!
82//! let ptr = my_obj.to_com_ptr::<IAnotherInterface>().unwrap();
83//! ptr.another_method();
84//! ```
85
86mod class;
87mod ptr;
88
89#[cfg(test)]
90mod tests;
91
92use std::ffi::c_void;
93
94pub use class::{Class, ComWrapper, Construct, Header, InterfaceList, MakeHeader, Wrapper};
95pub use ptr::{ComPtr, ComRef, SmartPtr};
96
97/// A 16-byte unique identifier for a COM interface.
98pub type Guid = [u8; 16];
99
100/// Implemented by interfaces that derive from the `IUnknown` interface (or an equivalent thereof).
101///
102/// Represents the base interface that all COM objects must implement and from which all COM
103/// interfaces must derive. Corresponds to the `IUnknown` interface. Includes functionality for
104/// reference counting ([`add_ref`](Self::add_ref) and [`release`](Self::release) and for
105/// dynamically casting between interface types ([`query_interface`](Self::query_interface)).
106///
107/// All interface types generated by `com-scrape` will implement this trait.
108pub trait Unknown {
109 /// Checks if an object implements the interface corresponding to the given GUID, and if so,
110 /// returns a corresponding interface pointer for the object and increments the object's
111 /// reference count.
112 unsafe fn query_interface(this: *mut Self, iid: &Guid) -> Option<*mut c_void>;
113
114 /// Increments an object's reference count and returns the resulting count.
115 unsafe fn add_ref(this: *mut Self) -> usize;
116
117 /// Decrements an object's reference count and returns the resulting count.
118 unsafe fn release(this: *mut Self) -> usize;
119}
120
121/// Implemented by all COM interface types.
122///
123/// # Safety
124///
125/// If a type `I` implements `Interface`, it must have the same layout as the pointer type
126/// `*const I::Vtbl`.
127///
128/// If `I::inherits(J::IID)` returns `true`, then the layout of `J::Vtbl` must be a prefix of the
129/// layout of `I::Vtbl`, i.e. a valid pointer to an instance of `I::Vtbl` must also be valid
130/// pointer to an instance of `J::Vtbl`.
131pub unsafe trait Interface: Unknown {
132 /// The type of the virtual method table for this interface.
133 type Vtbl;
134
135 /// A 16-byte unique identifier ([`Guid`]) for the COM interface represented by this type.
136 const IID: Guid;
137
138 /// Returns `true` if this interface transitively inherits from the interface identified by
139 /// `iid`.
140 ///
141 /// Note that this has safety implications; see the top-level documentation for [`Interface`].
142 fn inherits(iid: &Guid) -> bool;
143}
144
145/// Represents the "is-a" relationship for interfaces.
146///
147/// If interface `I` implements `Inherits<J>`, it is valid to cast a pointer of type `*mut I` to a
148/// pointer of type `*mut J` and to call any of `J`'s methods via that pointer.
149///
150/// The `Inherits` relation should be reflexive and transitive, i.e. `I: Inherits<I>` should be
151/// true for any type `I`, and if `I: Inherits<J>` and `J: Inherits<K>` are true, then
152/// `I: Inherits<K>` should also be true. However, this is not a safety requirement.
153///
154/// # Safety
155///
156/// [`Interface`] is a supertrait of `Inherits`, so all of `Interface`'s safety requirements also
157/// apply to `Inherits`. In particular, if `I` implements `Inherits`, it must have the same layout
158/// as the pointer type `*const I::Vtbl`.
159///
160/// If `I` implements `Inherits<J>`, then the layout of `J::Vtbl` must be a prefix of the layout of
161/// `I::Vtbl`, i.e. a valid pointer to an instance of `I::Vtbl` must also be a valid pointer to an
162/// instance of `J::Vtbl`.
163pub unsafe trait Inherits<I: Interface>: Interface {}
164
165unsafe impl<I: Interface> Inherits<I> for I {}