Tastenkombinationen

Drücken Sie oder , um zwischen den Kapiteln zu navigieren

Drücken Sie S oder /, um im Buch zu suchen

Drücken Sie ?, um diese Hilfe anzuzeigen

Drücken Sie Esc, um diese Hilfe auszublenden

Wie implementiere ich eine bestehende COM-Schnittstelle?

In einigen Fällen müssen Sie möglicherweise eine bestehende COM-Schnittstelle implementieren, anstatt einfach eine bestehende Implementierung aufzurufen, die vom Betriebssystem bereitgestellt wird. Hier sind die implement-Funktion und das Makro nützlich. Der windows-Crate bietet eine optionale Implementierungsunterstützung, die hinter der implement-Funktion verborgen ist. Sobald diese aktiviert ist, kann das implement-Makro verwendet werden, um beliebig viele COM-Schnittstellen zu implementieren. Das Makro kümmert sich selbst um die Implementierung von IUnknown.

Lassen Sie uns eine einfache Schnittstelle implementieren, die von Windows definiert wurde, um dies zu veranschaulichen. Die IPersist-Schnittstelle ist im Modul Win32::System::Com definiert, daher beginnen wir mit dem Hinzufügen einer Abhängigkeit vom windows-Crate und der Einbeziehung der Win32_System_Com-Funktion

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

Die implement-Funktion schaltet die Implementierungsunterstützung frei.

Das implement-Makro wird vom Modul windows::core bereitgestellt, daher halten wir die Dinge einfach, indem wir alles wie folgt einbeziehen

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

Nun ist es Zeit für die Implementierung

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

Das implement-Makro bietet die notwendige Implementierung für die Lebenszyklusverwaltung und die Schnittstellenerkennung von IUnknown für alle im Attribut enthaltenen Schnittstellen. In diesem Fall soll nur IPersist implementiert werden.

Die Implementierung selbst wird durch ein Trait definiert, das dem Muster <interface name>_Impl folgt, und es liegt an uns, es für unsere Implementierung wie folgt zu implementieren

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

Die IPersist-Schnittstelle, ursprünglich hier dokumentiert, hat eine einzige Methode, die eine GUID zurückgibt. Wir implementieren sie einfach, indem wir den Wert zurückgeben, der in unserer Implementierung enthalten ist. Der window-Crate und das implement-Makro kümmern sich um den Rest, indem sie den tatsächlichen COM-Virtual-Function-Call und das Virtual-Function-Table-Layout bereitstellen, das erforderlich ist, um dies in ein auf dem Heap zugewiesenes und referenzgezähltes COM-Objekt zu verwandeln.

Alles, was noch zu tun ist, ist, die Implementierung mithilfe des Into-Traits in die vom implement-Makro bereitgestellte COM-Implementierung zu verschieben oder zu verpacken

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

An diesem Punkt können wir persist einfach als das COM-Objekt behandeln, das es ist

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

Hier ist ein vollständiges Beispiel.