Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-COM interfaces do not support inheritance #2281

Open
DrChat opened this issue Jan 13, 2023 · 3 comments
Open

Non-COM interfaces do not support inheritance #2281

DrChat opened this issue Jan 13, 2023 · 3 comments
Labels
enhancement New feature or request

Comments

@DrChat
Copy link
Member

DrChat commented Jan 13, 2023

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):

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

@kennykerr
Copy link
Collaborator

Yep, I think I know what's wrong. The interface macro is a challenge. I'll be away for a few days but will take a closer look next week. Thanks for the repro!

@kennykerr kennykerr added the bug Something isn't working label Jan 13, 2023
@kennykerr
Copy link
Collaborator

I had a closer look. It's challenging because Rust macros don't have any context - they only see the tokens passed to the macro - so the interface macro doesn't know what IBase is and specifically whether it derives from IUnknown. We might have to find a more general way to describe interfaces so that it can support both scenarios.

@kennykerr kennykerr added enhancement New feature or request and removed bug Something isn't working labels Jan 18, 2023
@kennykerr
Copy link
Collaborator

Long term #1093 should make the need for the interface macro unnecessary but I'll give this some more thought in the meantime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants