#2281·windows-rs

`windows-rdl` non-COM interfaces do not support inheritance

Author: DrChatCreated Jan 13, 2023Updated Jul 7, 2026
Labelsenhancement

A familiar foe returns: I'm trying to create a compatibility library that binds XAudio 2.7 to XAudio 2.9 for a legacy game. However, I can't declare a few APIs using the #[interface] macro since they derive from IXAudio2Voice, which isn't a COM interface.

This is related to #2098 (and other issues/PRs related to that).

For a minimum repro, use the following test (which was modified from non_com_new.rs):

rust
#![allow(non_snake_case, non_camel_case_types)]

use windows::core::*;

// The `interface` macro defines a new local interface that does not derive from `IUnknown` and thus is not a COM interface at all.
#[interface]
unsafe trait IBase {
    unsafe fn BaseValue(&self) -> i32;
}

#[interface]
unsafe trait IDerived: IBase {
    unsafe fn DerivedValue(&self) -> i32;
}

struct Base(i32);

impl IBase_Impl for Base {
    unsafe fn BaseValue(&self) -> i32 {
        self.0
    }
}

struct Derived(i32, i32);

impl IBase_Impl for Derived {
    unsafe fn BaseValue(&self) -> i32 {
        self.0
    }
}

impl IDerived_Impl for Derived {
    unsafe fn DerivedValue(&self) -> i32 {
        self.1
    }
}

unsafe fn base_value(test: &IBase) -> i32 {
    test.BaseValue()
}

unsafe fn derived_value(test: &IDerived) -> i32 {
    test.DerivedValue()
}

#[test]
fn base() {
    unsafe {
        // Since the interface is not rooted in `IUnknown`, there's no COM-style lifetime and the resulting implementation merely
        // exists for the lifetime of the referenced implementation.
        let test = Base(456);
        let interface = IBase::new(&test);
        assert_eq!(base_value(&interface), 456);
        assert_eq!(interface.BaseValue(), 456);
    }
}

#[test]
fn derived() {
    unsafe {
        let test = Derived(123, 456);
        let interface = IDerived::new(&test);
        assert_eq!(base_value(&interface), 123);
        assert_eq!(interface.BaseValue(), 123);
        assert_eq!(derived_value(&interface), 456);
        assert_eq!(interface.DerivedValue(), 456);
    }
}

Specifically, this is the error thrown:

error[E0107]: this associated function takes 1 generic argument but 3 generic arguments were supplied
  --> crates\tests\interface\tests\non_com_new.rs:11:1
   |
11 | #[interface]
   | ^^^^^^^^^^^^
   | |
   | expected 1 generic argument
   | help: remove these generic arguments
   |

Cc @kennykerr (you seem to be the one most familiar with this class of issues)