-
Notifications
You must be signed in to change notification settings - Fork 511
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix bug in COM interface chain support (#3060)
The definition of a COM interface may inherit from another interface. These are known as "interface chains". The `#[implement]` macro allows designers to specify only the minimal set of interface chains that are needed for a given COM object implementation. The `#[implement]` macro (and the `#[interface]` macro) work together to pull in the implementations of all interfaces along the chain. Unfortunately there is a bug in the implementation of `QueryInterface` for interface chains. The current `QueryInterface` implementation will only check the IIDs of the interfaces at the root of the chian, i.e. the "most-derived" interface. `QueryInterface` will not search the IIDs of interfaces that are in the inheritance chain. This bug is demonstrated (detected) by the new unit tests in `crates/tests/implement_core/src/com_chain.rs`. This PR fixes the bug by generating an `fn matches()` method that checks the current IID and then checks the parent interface (if any) by calling its `match()` method. This fixes the unit test. Co-authored-by: Arlie Davis <ardavis@microsoft.com>
- Loading branch information
1 parent
71f8c2a
commit dbc3932
Showing
3 changed files
with
66 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use windows_core::*; | ||
|
||
#[interface("cccccccc-0000-0000-0000-000000000001")] | ||
unsafe trait IFoo: IUnknown {} | ||
|
||
#[interface("cccccccc-0000-0000-0000-000000000002")] | ||
unsafe trait IFoo2: IFoo {} | ||
|
||
#[interface("cccccccc-0000-0000-0000-000000000003")] | ||
unsafe trait IFoo3: IFoo2 {} | ||
|
||
// ObjectA implements a single interface chain, which consists of 3 different | ||
// interfaces: IFoo3, IFoo2, and IFoo. You do not need to explicitly list all | ||
// of the interfaces in the interface chain. Listing all of the interfaces is | ||
// less efficient because it generates redundant interface chains (pointer | ||
// fields in the the generated ObjectA_Impl type), which will never be used. | ||
#[implement(IFoo3)] | ||
struct ObjectWithChains {} | ||
|
||
impl IFoo_Impl for ObjectWithChains {} | ||
impl IFoo2_Impl for ObjectWithChains {} | ||
impl IFoo3_Impl for ObjectWithChains {} | ||
|
||
#[test] | ||
fn interface_chain_query() { | ||
let object = ComObject::new(ObjectWithChains {}); | ||
let unknown: IUnknown = object.to_interface(); | ||
let _foo: IFoo = unknown.cast().expect("QueryInterface for IFoo"); | ||
let _foo2: IFoo2 = unknown.cast().expect("QueryInterface for IFoo2"); | ||
let _foo3: IFoo3 = unknown.cast().expect("QueryInterface for IFoo3"); | ||
} | ||
|
||
// ObjectRedundantChains implements the same interfaces as ObjectWithChains, | ||
// but it defines more than one interface chain. This is unnecessary because it | ||
// is redundant, but we are verifying that this works. | ||
#[implement(IFoo3, IFoo2, IFoo)] | ||
struct ObjectRedundantChains {} | ||
|
||
impl IFoo_Impl for ObjectRedundantChains {} | ||
impl IFoo2_Impl for ObjectRedundantChains {} | ||
impl IFoo3_Impl for ObjectRedundantChains {} | ||
|
||
#[test] | ||
fn redundant_interface_chains() { | ||
let object = ComObject::new(ObjectRedundantChains {}); | ||
let unknown: IUnknown = object.to_interface(); | ||
let _foo: IFoo = unknown.cast().expect("QueryInterface for IFoo"); | ||
let _foo2: IFoo2 = unknown.cast().expect("QueryInterface for IFoo2"); | ||
let _foo3: IFoo3 = unknown.cast().expect("QueryInterface for IFoo3"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,5 @@ | |
#![cfg(test)] | ||
|
||
mod com_chain; | ||
mod com_object; |