@@ -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