microsoft / microsoft/windows-rs

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

Open
#2,281 3 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Rust
Stars
12.8k
Forks
665
Avg merge
7h 9m
Merged PRs (30d)
70

Description

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`):
```rs
#![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)

Contributor guide

Open the contributing guide

Research direction

Start with crates/tests/interface/tests/non_com_new.rs, which contains the minimum reproduction and was modified from the non-COM interface test. Trace the #[interface] macro handling for the IBase and IDerived inheritance shown there. Done means the test compiles and both base and derived method assertions pass without the generic-argument error.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.