Skip to content

Latest commit

Β 

History

History
97 lines (75 loc) Β· 3.77 KB

File metadata and controls

97 lines (75 loc) Β· 3.77 KB

windows-core

Core COM and WinRT type support shared by the windows-* crates.

windows-core is the foundation that nearly every other crate builds on. It provides the COM/WinRT runtime machinery β€” IUnknown, IInspectable, the Interface trait, reference counting, agile references, and weak references β€” along with GUID and re-exports of the result and string types.

It is also where you declare and implement your own COM and WinRT interfaces. The #[interface] and #[implement] macros live in the separate windows-interface and windows-implement crates only because Rust requires procedural macros to ship in their own proc-macro crate. They are part of windows-core β€” re-exported from it behind the default proc-macros feature and documented here rather than as standalone crates.

Declaring and implementing interfaces

Declare a COM interface as an unsafe trait deriving from IUnknown with #[interface] and its GUID, then provide a Rust type for it with #[implement]:

use windows_core::*;

#[interface("7e75ffe0-2f8c-4040-953e-b1f83a48f77b")]
unsafe trait IValue: IUnknown {
    unsafe fn value(&self) -> i32;
}

#[implement(IValue)]
struct Value {
    value: i32,
}

impl IValue_Impl for Value_Impl {
    unsafe fn value(&self) -> i32 {
        self.value
    }
}

fn main() {
    let object: IValue = Value { value: 42 }.into();
    assert_eq!(unsafe { object.value() }, 42);

    // COM identity: `cast` queries for another interface on the same object.
    let unknown: IUnknown = object.cast().unwrap();
    let again: IValue = unknown.cast().unwrap();
    assert_eq!(unsafe { again.value() }, 42);
}

#[interface] generates the vtable, the safe caller-side wrappers, and the IValue_Impl trait. #[implement] generates the Value_Impl wrapper that carries the vtable pointers and reference count; you write the methods in impl IValue_Impl for Value_Impl. Converting the struct .into() an interface yields a reference-counted COM object, and cast moves between interfaces on the same object.

Without the proc macros

Disabling the default proc-macros feature drops the syn/quote/proc-macro2 build dependencies. The interface_decl! and implement_decl! declarative macro_rules! macros then cover the common case β€” an always-agile type implementing one or more IUnknown-derived interfaces β€” without proc macros. They are more verbose (every identifier and the IID must be spelled out) and narrower in scope; see the interface_macro and implement_macro module docs for the grammar and limits. windows-core uses them internally so it can build with proc-macros disabled.


Internal documentation

The remainder of this page covers how the crate is built and maintained. It is for contributors and is not needed to use windows-core.

How it's built

src/bindings.rs is generated by tool_bindings from crates/tools/bindings/src/core.txt. The hand-written modules (agile_reference, com_object, compose, event, …) provide the COM runtime support. The #[implement]/#[interface] proc macros are re-exported from the windows-implement/windows-interface crates behind the proc-macros feature, and the implement_macro/interface_macro modules supply the implement_decl!/interface_decl! declarative equivalents used when that feature is off.

Testing

Run cargo test -p windows-core; see also the workspace test crates.