How do I implement an existing COM interface?

In some cases, you may need to implement an existing COM interface rather than simply calling an existing implementation provided by the operating system. This is where the implement feature and macro come in handy. The windows crate provides optional implementation support hidden behind the implement feature. Once enabled, the implement macro may be used to implement any number of COM interfaces. The macro takes care of implementing IUnknown itself.

Let's implement a simple interface defined by Windows to illustrate. The IPersist interface is defined in the Win32::System::Com module, so we'll start by adding a dependency on the windows crate and include the Win32_System_Com feature:

[dependencies.windows]
version = "0.52"
features = [
    "implement",
    "Win32_System_Com",
]

The implement feature unlocks the implementation support.

The implement macro is included by the windows::core module so we'll keep things simple by including it all as follows:

#![allow(unused)]
fn main() {
use windows::{core::*, Win32::System::Com::*};
}

Now its time for the implementation:

#![allow(unused)]
fn main() {
#[implement(IPersist)]
struct Persist(GUID);
}

The implement macro will provide the necessary implementation for the IUnknown interface's lifetime management and interface discovery for whatever interfaces are included in the attribute. In this case, only IPersist is to be implemented.

The implementation itself is defined by a trait that follows the <interface name>_Impl pattern and its up to us to implement it for our implementation as follows:

#![allow(unused)]
fn main() {
impl IPersist_Impl for Persist {
    fn GetClassID(&self) -> Result<GUID> {
        Ok(self.0)
    }
}
}

The IPersist interface, originally documented here, has a single method that returns a GUID, so we'll just implement it by returning the value contained within our implementation. The window crate and implement macro will take care of the rest by providing the actual COM virtual function call and virtual function table layout needed to turn this into a heap-allocated and reference-counted COM object.

All that remains is to move, or box, the implementation into the COM implementation provided by the implement macro through the Into trait:

#![allow(unused)]
fn main() {
let guid = GUID::new()?;
let persist: IPersist = Persist(guid).into();
}

At this point, we can simply treat persist as the COM object that it is:

#![allow(unused)]
fn main() {
let guid2 = unsafe { persist.GetClassID()? };
assert_eq!(guid, guid2);
println!("{:?}", guid);
}

Here's a complete example.