impl Interface { /// Generates all the code needed for a COM interface fn gen_tokens(&self, guid: &Guid) -> syn::Result<proc_macro2::TokenStream> { let vis = &self.visibility; let name = &self.name; let docs = &self.docs; let parent = self.parent_type(); let vtable_name = quote::format_ident!("{}_Vtbl", name); let guid = guid.to_tokens()?; let implementation = self.gen_implementation(); let com_trait = self.get_com_trait(); let vtable = self.gen_vtable(&vtable_name); let conversions = self.gen_conversions();
/// Generates the methods users can call on the COM interface pointer fn gen_implementation(&self) -> proc_macro2::TokenStream { let name = &self.name; let methods = self
.methods
.iter()
.map(|m| { let vis = &m.visibility; let name = &m.name;
let generics = m.gen_consume_generics(); let params = m.gen_consume_params(); let args = m.gen_consume_args(); let ret = &m.ret;
fn get_com_trait(&self) -> proc_macro2::TokenStream { let name = quote::format_ident!("{}_Impl", self.name); let vis = &self.visibility; let methods = self
.methods
.iter()
.map(|m| { let name = &m.name; let docs = &m.docs; let args = m.gen_args(); let ret = &m.ret;
quote! { #(#docs)* unsafefn#name(&self, #(#args),*) #ret;
}
})
.collect::<Vec<_>>(); let parent = self.parent_trait_constraint();
/// Generates the vtable for a COM interface fn gen_vtable(&self, vtable_name: &syn::Ident) -> proc_macro2::TokenStream { let vis = &self.visibility; let name = &self.name; let trait_name = quote::format_ident!("{}_Impl", name); let implvtbl_name = quote::format_ident!("{}_ImplVtbl", name);
let vtable_entries = self
.methods
.iter()
.map(|m| { let name = &m.name; let ret = &m.ret; let args = m.gen_args();
let parent_vtable_generics = quote!(Identity, OFFSET); let parent_vtable = self.parent_vtable();
// or_parent_matches will be `|| parent::matches(iid)` if this interface inherits from another // interface (except for IUnknown) or will be empty if this is not applicable. This is what allows // QueryInterface to work correctly for all interfaces in an inheritance chain, e.g. // IFoo3 derives from IFoo2 derives from IFoo. // // We avoid matching IUnknown because object identity depends on the uniqueness of the IUnknown pointer. let or_parent_matches = match parent_vtable.as_ref() {
Some(parent) if !self.parent_is_iunknown() => quote! (|| <#parent>::matches(iid)),
_ => quote!(),
};
let functions = self
.methods
.iter()
.map(|m| { let name = &m.name; let args = m.gen_args(); let params = &m
.args
.iter()
.map(|a| { let pat = &a.pat;
quote! { #pat }
})
.collect::<Vec<_>>(); let ret = &m.ret;
let ret = if m.is_result() {
quote! { -> ::windows_core::HRESULT }
} else {
quote! { #ret }
};
if parent_vtable.is_some() {
quote! { unsafeextern"system"fn#name<
Identity: ::windows_core::IUnknownImpl, const OFFSET: isize
>(
this: *mut ::core::ffi::c_void, // <-- This is the COM "this" pointer, which is not the same as &T or &T_Impl. #(#args),*
) #ret where
Identity : #trait_name
{ // This step is essentially a virtual dispatch adjustor thunk. Its purpose is to adjust // the "this" pointer from the address used by the COM interface to the root of the // MyApp_Impl object. Since a given MyApp_Impl may implement more than one COM interface // (and more than one COM interface chain), we need to know how to get from COM's "this" // back to &MyApp_Impl. The OFFSET constant gives us the value (in pointer-sized units). let this_outer: &Identity = &*((this as *const *const ()).offset(OFFSET) as *const Identity);
// Last, we invoke the implementation function. // We use explicit <Impl as IFoo_Impl> so that we can select the correct method // for situations where IFoo3 derives from IFoo2 and both declare a method with // the same name.
<Identity as#trait_name>::#name(this_outer, #(#params),*).into()
}
}
} else {
quote! { unsafeextern"system"fn#name<Impl: #trait_name>(this: *mut ::core::ffi::c_void, #(#args),*) #ret { let this = (this as *mut *mut ::core::ffi::c_void) as *const ::windows_core::ScopedHeap; let this = (*this).this as *constImpl;
(*this).#name(#(#params),*).into()
}
}
}
})
.collect::<Vec<_>>();
iflet Some(parent_vtable) = parent_vtable { let entries = self
.methods
.iter()
.map(|m| { let name = &m.name;
quote!(#name: #name::<Identity, OFFSET>)
})
.collect::<Vec<_>>();
fn ensure_length(
part: Option<&str>,
index: usize,
length: usize,
span: proc_macro2::Span,
) -> syn::Result<String> { let part = match part {
Some(p) => p,
None => { return Err(syn::Error::new(
span,
format!("The IID missing part at index {index}"),
))
}
};
if part.len() != length { return Err(syn::Error::new(
span,
format!( "The IID part at index {} must be {} characters long but was {} characters",
index,
length,
part.len()
),
));
}
let data1 = hex_lit(&chunks[0]); let data2 = hex_lit(&chunks[1]); let data3 = hex_lit(&chunks[2]); let (data4_1, data4_2) = chunks[3].split_at(2); let data4_1 = hex_lit(data4_1); let data4_2 = hex_lit(data4_2); let (data4_3, rest) = chunks[4].split_at(2); let data4_3 = hex_lit(data4_3);
let (data4_4, rest) = rest.split_at(2); let data4_4 = hex_lit(data4_4);
let (data4_5, rest) = rest.split_at(2); let data4_5 = hex_lit(data4_5);
let (data4_6, rest) = rest.split_at(2); let data4_6 = hex_lit(data4_6);
impl syn::parse::Parse for InterfaceMethod { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { let docs = input.call(syn::Attribute::parse_outer)?; let visibility = input.parse::<syn::Visibility>()?; let method = input.parse::<syn::TraitItemFn>()?;
unexpected_token!(docs.iter().find(|a| !a.path().is_ident("doc")), "attribute");
unexpected_token!(method.default, "default method implementation"); let sig = method.sig;
unexpected_token!(sig.abi, "abi declaration");
unexpected_token!(sig.asyncness, "async declaration");
unexpected_token!(sig.generics.params.iter().next(), "generics declaration");
unexpected_token!(sig.constness, "const declaration");
expected_token!(
sig.receiver(), "the method to have &self as its first argument"
);
unexpected_token!(sig.variadic, "variadic args"); let args = sig
.inputs
.into_iter()
.filter_map(|a| match a {
syn::FnArg::Receiver(_) => None,
syn::FnArg::Typed(p) => Some(p),
})
.map(|p| {
Ok(InterfaceMethodArg {
ty: p.ty,
pat: p.pat,
})
})
.collect::<Result<Vec<InterfaceMethodArg>, syn::Error>>()?;
let ret = sig.output;
Ok(InterfaceMethod {
name: sig.ident,
visibility,
args,
ret,
docs,
})
}
}
/// An argument to an interface method struct InterfaceMethodArg { /// The type of the argument pub ty: Box<syn::Type>, /// The name of the argument pub pat: Box<syn::Pat>,
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.