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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
//! Support types and traits for bindings generated by `com-scrape`.
//!
//! [`ComPtr`] and [`ComRef`] are smart pointers for interacting with COM objects (calling methods,
//! casting between interfaces, and managing reference counts). The [`Class`] trait can be used for
//! defining COM classes in Rust, and [`ComWrapper`] is a smart pointer used for instantiating
//! those classes.
//!
//! # Reference counting
//!
//! COM objects are reference-counted. The [`ComPtr`] and [`ComRef`] smart pointers manage this
//! automatically where possible, but the function signatures generated by `com-scrape` still pass
//! COM objects as raw pointers, and care must be taken to handle issues of ownership correctly
//! when converting between [`ComPtr`] or [`ComRef`] and raw pointers at these boundaries.
//!
//! A thorough overview of how to manage reference counts for COM objects in a variety of situations
//! can be found on the ["Rules for Managing Reference Counts"][rules] page in the Microsoft COM
//! documentation, and the documentation for each individual [`ComPtr`] and[`ComRef`] method
//! specifies its effect on an object's reference count. However, the following rules of thumb
//! should suffice in the majority of situations:
//!
//! 1. When passing an interface pointer as a function parameter, use [`ComPtr::as_ptr`] to obtain a
//! raw pointer from a [`ComPtr`], or use [`ComRef::as_ptr`] to obtain a raw pointer from a
//! [`ComRef`].
//!
//! 2. When receiving an interface pointer as the return value of a function (or via an out
//! parameter), always use [`ComPtr::from_raw`] to obtain a [`ComPtr`] from the raw pointer.
//!
//! 3. When receiving an interface pointer as a function parameter, always use
//! [`ComRef::from_raw`] to obtain a [`ComRef`] from the raw pointer. If the received interface
//! pointer will be stored beyond the duration of the current function, use
//! [`ComRef::to_com_ptr`] to upgrade the [`ComRef`] to a [`ComPtr`].
//!
//! 4. When returning an interface pointer from a function (or when returning it via an out
//! parameter), always use [`ComPtr::into_raw`] to obtain a raw pointer from a [`ComPtr`].
//!
//! [rules]: https://learn.microsoft.com/en-us/windows/win32/com/rules-for-managing-reference-counts
//!
//! # Implementing COM interfaces from Rust
//!
//! The [`Class`] trait can be used to define COM classes in Rust, and the [`ComWrapper`] smart
//! pointer can be used to instantiate objects of these classes. To define a COM class, start by
//! defining a Rust type:
//!
//! ```ignore
//! struct MyClass { /* ... */ }
//! ```
//!
//! Then implement the desired interface traits for the type:
//!
//! ```ignore
//! impl ISomeInterfaceTrait for MyClass {
//! unsafe fn some_method(&self) {
//! /* ... */
//! }
//! }
//!
//! impl IAnotherInterfaceTrait for MyClass {
//! unsafe fn another_method(&self) {
//! /* ... */
//! }
//! }
//! ```
//!
//! Finally, implement the [`Class`] trait for the type, specifying the set of COM interfaces as a
//! tuple:
//!
//! ```ignore
//! impl Class for MyClass {
//! type Interfaces = (ISomeInterface, IAnotherInterface);
//! }
//! ```
//!
//! With these definitions in place, [`ComWrapper`] can be used to instantiate a COM object
//! supporting the above interfaces:
//!
//! ```ignore
//! let my_obj = ComWrapper::new(MyClass);
//!
//! let ptr = my_obj.to_com_ptr::<ISomeInterface>().unwrap();
//! ptr.some_method();
//!
//! let ptr = my_obj.to_com_ptr::<IAnotherInterface>().unwrap();
//! ptr.another_method();
//! ```
mod class;
mod ptr;
#[cfg(test)]
mod tests;
use std::ffi::c_void;
pub use class::{Class, ComWrapper, Construct, Header, InterfaceList, MakeHeader, Wrapper};
pub use ptr::{ComPtr, ComRef, SmartPtr};
/// A 16-byte unique identifier for a COM interface.
pub type Guid = [u8; 16];
/// Implemented by interfaces that derive from the `IUnknown` interface (or an equivalent thereof).
///
/// Represents the base interface that all COM objects must implement and from which all COM
/// interfaces must derive. Corresponds to the `IUnknown` interface. Includes functionality for
/// reference counting ([`add_ref`](Self::add_ref) and [`release`](Self::release) and for
/// dynamically casting between interface types ([`query_interface`](Self::query_interface)).
///
/// All interface types generated by `com-scrape` will implement this trait.
pub trait Unknown {
/// Checks if an object implements the interface corresponding to the given GUID, and if so,
/// returns a corresponding interface pointer for the object and increments the object's
/// reference count.
unsafe fn query_interface(this: *mut Self, iid: &Guid) -> Option<*mut c_void>;
/// Increments an object's reference count and returns the resulting count.
unsafe fn add_ref(this: *mut Self) -> usize;
/// Decrements an object's reference count and returns the resulting count.
unsafe fn release(this: *mut Self) -> usize;
}
/// Implemented by all COM interface types.
///
/// # Safety
///
/// If a type `I` implements `Interface`, it must have the same layout as the pointer type
/// `*const I::Vtbl`.
///
/// If `I::inherits(J::IID)` returns `true`, then the layout of `J::Vtbl` must be a prefix of the
/// layout of `I::Vtbl`, i.e. a valid pointer to an instance of `I::Vtbl` must also be valid
/// pointer to an instance of `J::Vtbl`.
pub unsafe trait Interface: Unknown {
/// The type of the virtual method table for this interface.
type Vtbl;
/// A 16-byte unique identifier ([`Guid`]) for the COM interface represented by this type.
const IID: Guid;
/// Returns `true` if this interface transitively inherits from the interface identified by
/// `iid`.
///
/// Note that this has safety implications; see the top-level documentation for [`Interface`].
fn inherits(iid: &Guid) -> bool;
}
/// Represents the "is-a" relationship for interfaces.
///
/// If interface `I` implements `Inherits<J>`, it is valid to cast a pointer of type `*mut I` to a
/// pointer of type `*mut J` and to call any of `J`'s methods via that pointer.
///
/// The `Inherits` relation should be reflexive and transitive, i.e. `I: Inherits<I>` should be
/// true for any type `I`, and if `I: Inherits<J>` and `J: Inherits<K>` are true, then
/// `I: Inherits<K>` should also be true. However, this is not a safety requirement.
///
/// # Safety
///
/// [`Interface`] is a supertrait of `Inherits`, so all of `Interface`'s safety requirements also
/// apply to `Inherits`. In particular, if `I` implements `Inherits`, it must have the same layout
/// as the pointer type `*const I::Vtbl`.
///
/// If `I` implements `Inherits<J>`, then the layout of `J::Vtbl` must be a prefix of the layout of
/// `I::Vtbl`, i.e. a valid pointer to an instance of `I::Vtbl` must also be a valid pointer to an
/// instance of `J::Vtbl`.
pub unsafe trait Inherits<I: Interface>: Interface {}
unsafe impl<I: Interface> Inherits<I> for I {}