Skip to content

Commit d7343bc

Browse files
authored
Add support for non-COM interfaces (#2066)
1 parent d0ab3b5 commit d7343bc

File tree

31 files changed

+2667
-1697
lines changed

31 files changed

+2667
-1697
lines changed

crates/libs/bindgen/src/classes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ fn gen_class(gen: &Gen, def: TypeDef) -> TokenStream {
104104

105105
tokens.combine(&gen.interface_core_traits(def, &[], &name, &TokenStream::new(), &TokenStream::new(), &features));
106106
tokens.combine(&gen.interface_winrt_trait(def, &[], &name, &TokenStream::new(), &TokenStream::new(), &features));
107-
tokens.combine(&gen.interface_trait(def, &[], &name, &TokenStream::new(), &features));
107+
tokens.combine(&gen.interface_trait(def, &[], &name, &TokenStream::new(), &features, true));
108108
tokens.combine(&gen.runtime_name_trait(def, &[], &name, &TokenStream::new(), &features));
109109
tokens.combine(&gen.async_get(def, &[], &name, &TokenStream::new(), &TokenStream::new(), &features));
110110
tokens.combine(&iterators::gen(gen, def, &[], &name, &TokenStream::new(), &TokenStream::new(), &cfg));

crates/libs/bindgen/src/delegates.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ fn gen_win_delegate(gen: &Gen, def: TypeDef) -> TokenStream {
142142
};
143143

144144
tokens.combine(&gen.interface_core_traits(def, generics, &ident, &constraints, &phantoms, &features));
145-
tokens.combine(&gen.interface_trait(def, generics, &ident, &constraints, &features));
145+
tokens.combine(&gen.interface_trait(def, generics, &ident, &constraints, &features, true));
146146
tokens.combine(&gen.interface_winrt_trait(def, generics, &ident, &constraints, &phantoms, &features));
147147
tokens.combine(&gen.interface_vtbl(def, generics, &ident, &constraints, &features));
148148
tokens

crates/libs/bindgen/src/gen.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ impl<'a> Gen<'a> {
707707
}
708708
}
709709

710-
pub fn interface_trait(&self, def: TypeDef, generics: &[Type], ident: &TokenStream, constraints: &TokenStream, features: &TokenStream) -> TokenStream {
710+
pub fn interface_trait(&self, def: TypeDef, generics: &[Type], ident: &TokenStream, constraints: &TokenStream, features: &TokenStream, has_unknown_base: bool) -> TokenStream {
711711
if let Some(default) = self.reader.type_def_default_interface(def) {
712712
let default_name = self.type_name(&default);
713713
let vtbl = self.type_vtbl_name(&default);
@@ -737,16 +737,24 @@ impl<'a> Gen<'a> {
737737
::windows::core::GUID::from_signature(<Self as ::windows::core::RuntimeType>::SIGNATURE)
738738
}
739739
};
740-
quote! {
740+
741+
let mut tokens = quote! {
741742
#features
742743
unsafe impl<#constraints> ::windows::core::Vtable for #ident {
743744
type Vtable = #vtbl;
744745
}
745-
#features
746-
unsafe impl<#constraints> ::windows::core::Interface for #ident {
747-
const IID: ::windows::core::GUID = #guid;
748-
}
746+
};
747+
748+
if has_unknown_base {
749+
tokens.combine(&quote! {
750+
#features
751+
unsafe impl<#constraints> ::windows::core::Interface for #ident {
752+
const IID: ::windows::core::GUID = #guid;
753+
}
754+
});
749755
}
756+
757+
tokens
750758
}
751759
}
752760
pub fn interface_vtbl(&self, def: TypeDef, generics: &[Type], _ident: &TokenStream, constraints: &TokenStream, features: &TokenStream) -> TokenStream {

crates/libs/bindgen/src/implements.rs

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream {
99
let type_ident = to_ident(gen.reader.type_def_name(def));
1010
let impl_ident = type_ident.join("_Impl");
1111
let vtbl_ident = type_ident.join("_Vtbl");
12+
let implvtbl_ident = impl_ident.join("Vtbl");
1213
let constraints = gen.generic_constraints(generics);
1314
let generic_names = gen.generic_names(generics);
1415
let named_phantoms = gen.generic_named_phantoms(generics);
@@ -17,6 +18,7 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream {
1718
let mut requires = quote! {};
1819
let type_ident = quote! { #type_ident<#generic_names> };
1920
let vtables = gen.reader.type_def_vtables(def);
21+
let has_unknown_base = matches!(vtables.first(), Some(Type::IUnknown));
2022

2123
fn gen_required_trait(gen: &Gen, def: TypeDef, generics: &[Type]) -> TokenStream {
2224
let name = gen.type_def_name_imp(def, generics, "_Impl");
@@ -83,24 +85,38 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream {
8385

8486
let invoke_upcall = if gen.reader.type_def_flags(def).winrt() { winrt_methods::gen_upcall(gen, &signature, quote! { this.#name }) } else { com_methods::gen_upcall(gen, &signature, quote! { this.#name }) };
8587

86-
quote! {
87-
unsafe extern "system" fn #name<#constraints Identity: ::windows::core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize> #vtbl_signature {
88-
// offset the `this` pointer by `OFFSET` times the size of a pointer and cast it as an IUnknown implementation
89-
let this = (this as *const *const ()).offset(OFFSET) as *const Identity;
90-
let this = (*this).get_impl();
91-
#invoke_upcall
88+
if has_unknown_base {
89+
quote! {
90+
unsafe extern "system" fn #name<#constraints Identity: ::windows::core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize> #vtbl_signature {
91+
// offset the `this` pointer by `OFFSET` times the size of a pointer and cast it as an IUnknown implementation
92+
let this = (this as *const *const ()).offset(OFFSET) as *const Identity;
93+
let this = (*this).get_impl();
94+
#invoke_upcall
95+
}
96+
}
97+
} else {
98+
quote! {
99+
unsafe extern "system" fn #name<Impl: #impl_ident> #vtbl_signature {
100+
let this = (this as *mut *mut ::core::ffi::c_void) as *const ::windows::core::ScopedHeap;
101+
let this = &*((*this).this as *const Impl);
102+
#invoke_upcall
103+
}
92104
}
93105
}
94106
});
95107

96108
let mut methods = quote! {};
97109

98-
match gen.reader.type_def_vtables(def).last() {
110+
match vtables.last() {
99111
Some(Type::IUnknown) => methods.combine(&quote! { base__: ::windows::core::IUnknown_Vtbl::new::<Identity, OFFSET>(), }),
100112
Some(Type::IInspectable) => methods.combine(&quote! { base__: ::windows::core::IInspectable_Vtbl::new::<Identity, #type_ident, OFFSET>(), }),
101113
Some(Type::TypeDef((def, generics))) => {
102114
let name = gen.type_def_name_imp(*def, generics, "_Vtbl");
103-
methods.combine(&quote! { base__: #name::new::<Identity, Impl, OFFSET>(), });
115+
if has_unknown_base {
116+
methods.combine(&quote! { base__: #name::new::<Identity, Impl, OFFSET>(), });
117+
} else {
118+
methods.combine(&quote! { base__: #name::new::<Impl>(), });
119+
}
104120
}
105121
_ => {}
106122
}
@@ -110,26 +126,64 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream {
110126

111127
for method in gen.reader.type_def_methods(def) {
112128
let name = method_names.add(gen, method);
113-
methods.combine(&quote! { #name: #name::<#generic_names Identity, Impl, OFFSET>, });
129+
if has_unknown_base {
130+
methods.combine(&quote! { #name: #name::<#generic_names Identity, Impl, OFFSET>, });
131+
} else {
132+
methods.combine(&quote! { #name: #name::<Impl>, });
133+
}
114134
}
115135

116-
quote! {
117-
#features
118-
pub trait #impl_ident<#generic_names> : Sized #requires where #constraints {
119-
#(#method_traits)*
136+
if has_unknown_base {
137+
quote! {
138+
#features
139+
pub trait #impl_ident<#generic_names> : Sized #requires where #constraints {
140+
#(#method_traits)*
141+
}
142+
#runtime_name
143+
#features
144+
impl<#constraints> #vtbl_ident<#generic_names> {
145+
pub const fn new<Identity: ::windows::core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize>() -> #vtbl_ident<#generic_names> {
146+
#(#method_impls)*
147+
Self{
148+
#methods
149+
#(#named_phantoms)*
150+
}
151+
}
152+
pub fn matches(iid: &windows::core::GUID) -> bool {
153+
#matches
154+
}
155+
}
120156
}
121-
#runtime_name
122-
#features
123-
impl<#constraints> #vtbl_ident<#generic_names> {
124-
pub const fn new<Identity: ::windows::core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize>() -> #vtbl_ident<#generic_names> {
125-
#(#method_impls)*
126-
Self{
127-
#methods
128-
#(#named_phantoms)*
157+
} else {
158+
quote! {
159+
#features
160+
pub trait #impl_ident : Sized #requires {
161+
#(#method_traits)*
162+
}
163+
#features
164+
impl #vtbl_ident {
165+
pub const fn new<Impl: #impl_ident>() -> #vtbl_ident {
166+
#(#method_impls)*
167+
Self{
168+
#methods
169+
#(#named_phantoms)*
170+
}
129171
}
130172
}
131-
pub fn matches(iid: &windows::core::GUID) -> bool {
132-
#matches
173+
#[doc(hidden)]
174+
#features
175+
struct #implvtbl_ident<T: #impl_ident> (::std::marker::PhantomData<T>);
176+
#features
177+
impl<T: #impl_ident> #implvtbl_ident<T> {
178+
const VTABLE: #vtbl_ident = #vtbl_ident::new::<T>();
179+
}
180+
#features
181+
impl #type_ident {
182+
pub fn new<'a, T: #impl_ident>(this: &'a T) -> ::windows::core::ScopedInterface<'a, Self> {
183+
let this = ::windows::core::ScopedHeap { vtable: &#implvtbl_ident::<T>::VTABLE as *const _ as *const _, this: this as *const _ as *const _ };
184+
let this = ::std::mem::ManuallyDrop::new(::std::boxed::Box::new(this));
185+
unsafe { ::windows::core::ScopedInterface::new(::std::mem::transmute(&this.vtable)) }
186+
}
133187
}
134188
}
135189
}

0 commit comments

Comments
 (0)