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

Support COM-style query signatures with unconventional parameter positions #1805

Merged
merged 9 commits into from
Jun 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ jobs:
cargo clippy -p test_ntstatus &&
cargo clippy -p test_null_result &&
cargo clippy -p test_properties &&
cargo clippy -p test_query_signature &&
cargo clippy -p test_return_struct &&
cargo clippy -p test_string_param &&
cargo clippy -p test_structs &&
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ jobs:
cargo test --target ${{ matrix.target }} -p test_component &&
cargo test --target ${{ matrix.target }} -p test_component_client &&
cargo test --target ${{ matrix.target }} -p test_const_fields &&
cargo clean &&
cargo test --target ${{ matrix.target }} -p test_core &&
cargo clean &&
cargo test --target ${{ matrix.target }} -p test_data_object &&
cargo test --target ${{ matrix.target }} -p test_debug &&
cargo test --target ${{ matrix.target }} -p test_deprecated &&
Expand All @@ -152,6 +152,7 @@ jobs:
cargo test --target ${{ matrix.target }} -p test_ntstatus &&
cargo test --target ${{ matrix.target }} -p test_null_result &&
cargo test --target ${{ matrix.target }} -p test_properties &&
cargo test --target ${{ matrix.target }} -p test_query_signature &&
cargo test --target ${{ matrix.target }} -p test_return_struct &&
cargo test --target ${{ matrix.target }} -p test_string_param &&
cargo test --target ${{ matrix.target }} -p test_structs &&
Expand Down
43 changes: 21 additions & 22 deletions crates/libs/bindgen/src/com_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,38 +20,37 @@ pub fn gen(gen: &Gen, def: TypeDef, kind: InterfaceKind, method: MethodDef, meth
bases.combine(&quote! { .base__ });
}

match gen.reader.signature_kind(&signature) {
SignatureKind::Query => {
let leading_params = &signature.params[..signature.params.len() - 2];
let args = gen.win32_args(leading_params);
let params = gen.win32_params(leading_params);
let kind = gen.reader.signature_kind(&signature);
match kind {
SignatureKind::Query(_) => {
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);

quote! {
#doc
#features
pub unsafe fn #name<#constraints T: ::windows::core::Interface>(&self, #params) -> ::windows::core::Result<T> {
let mut result__ = ::core::option::Option::None;
(::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args &<T as ::windows::core::Interface>::IID, &mut result__ as *mut _ as *mut _).and_some(result__)
(::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args).and_some(result__)
}
}
}
SignatureKind::QueryOptional => {
let leading_params = &signature.params[..signature.params.len() - 2];
let args = gen.win32_args(leading_params);
let params = gen.win32_params(leading_params);
SignatureKind::QueryOptional(_) => {
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);

quote! {
#doc
#features
pub unsafe fn #name<#constraints T: ::windows::core::Interface>(&self, #params result__: *mut ::core::option::Option<T>) -> ::windows::core::Result<()> {
(::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args &<T as ::windows::core::Interface>::IID, result__ as *mut _ as *mut _).ok()
(::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args).ok()
}
}
}
SignatureKind::ResultValue => {
let leading_params = &signature.params[..signature.params.len() - 1];
let args = gen.win32_args(leading_params);
let params = gen.win32_params(leading_params);
let args = gen.win32_args(leading_params, kind);
let params = gen.win32_params(leading_params, kind);
let return_type = signature.params[signature.params.len() - 1].ty.deref();
let return_type_tokens = gen.type_name(&return_type);
let abi_return_type_tokens = gen.type_abi_name(&return_type);
Expand All @@ -67,8 +66,8 @@ pub fn gen(gen: &Gen, def: TypeDef, kind: InterfaceKind, method: MethodDef, meth
}
}
SignatureKind::ResultVoid => {
let args = gen.win32_args(&signature.params);
let params = gen.win32_params(&signature.params);
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);

quote! {
#doc
Expand All @@ -79,8 +78,8 @@ pub fn gen(gen: &Gen, def: TypeDef, kind: InterfaceKind, method: MethodDef, meth
}
}
SignatureKind::ReturnStruct => {
let args = gen.win32_args(&signature.params);
let params = gen.win32_params(&signature.params);
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);
let return_type = gen.type_name(&signature.return_type.unwrap());

quote! {
Expand All @@ -94,8 +93,8 @@ pub fn gen(gen: &Gen, def: TypeDef, kind: InterfaceKind, method: MethodDef, meth
}
}
SignatureKind::PreserveSig => {
let args = gen.win32_args(&signature.params);
let params = gen.win32_params(&signature.params);
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);
let return_type = gen.return_sig(&signature);

quote! {
Expand All @@ -107,8 +106,8 @@ pub fn gen(gen: &Gen, def: TypeDef, kind: InterfaceKind, method: MethodDef, meth
}
}
SignatureKind::ReturnVoid => {
let args = gen.win32_args(&signature.params);
let params = gen.win32_params(&signature.params);
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);

quote! {
#doc
Expand Down Expand Up @@ -139,7 +138,7 @@ pub fn gen_upcall(gen: &Gen, sig: &Signature, inner: TokenStream) -> TokenStream
}
}
}
SignatureKind::Query | SignatureKind::QueryOptional | SignatureKind::ResultVoid => {
SignatureKind::Query(_) | SignatureKind::QueryOptional(_) | SignatureKind::ResultVoid => {
let invoke_args = sig.params.iter().map(|param| gen_win32_invoke_arg(gen, param));

quote! {
Expand Down
41 changes: 20 additions & 21 deletions crates/libs/bindgen/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
let doc = gen.cfg_doc(&cfg);
let features = gen.cfg_features(&cfg);

match gen.reader.signature_kind(&signature) {
SignatureKind::Query => {
let leading_params = &signature.params[..signature.params.len() - 2];
let args = gen.win32_args(leading_params);
let params = gen.win32_params(leading_params);
let kind = gen.reader.signature_kind(&signature);
match kind {
SignatureKind::Query(_) => {
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);

quote! {
#doc
Expand All @@ -82,17 +82,16 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
fn #name(#(#abi_params),*) #abi_return_type;
}
let mut result__ = ::core::option::Option::None;
#name(#args &<T as ::windows::core::Interface>::IID, &mut result__ as *mut _ as *mut _).and_some(result__)
#name(#args).and_some(result__)
}
#[cfg(not(windows))]
unimplemented!("Unsupported target OS");
}
}
}
SignatureKind::QueryOptional => {
let leading_params = &signature.params[..signature.params.len() - 2];
let args = gen.win32_args(leading_params);
let params = gen.win32_params(leading_params);
SignatureKind::QueryOptional(_) => {
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);

quote! {
#doc
Expand All @@ -105,7 +104,7 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
extern "system" {
fn #name(#(#abi_params),*) #abi_return_type;
}
#name(#args &<T as ::windows::core::Interface>::IID, result__ as *mut _ as *mut _).ok()
#name(#args).ok()
}
#[cfg(not(windows))]
unimplemented!("Unsupported target OS");
Expand All @@ -114,8 +113,8 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
}
SignatureKind::ResultValue => {
let leading_params = &signature.params[..signature.params.len() - 1];
let args = gen.win32_args(leading_params);
let params = gen.win32_params(leading_params);
let args = gen.win32_args(leading_params, kind);
let params = gen.win32_params(leading_params, kind);
let return_type = signature.params[signature.params.len() - 1].ty.deref();
let return_type_tokens = gen.type_name(&return_type);
let abi_return_type_tokens = gen.type_abi_name(&return_type);
Expand All @@ -140,8 +139,8 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
}
}
SignatureKind::ResultVoid => {
let args = gen.win32_args(&signature.params);
let params = gen.win32_params(&signature.params);
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);

quote! {
#doc
Expand All @@ -163,8 +162,8 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
}
SignatureKind::ReturnStruct | SignatureKind::PreserveSig => {
if handle_last_error(gen, def, &signature) {
let args = gen.win32_args(&signature.params);
let params = gen.win32_params(&signature.params);
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);
let return_type = gen.type_name(&signature.return_type.unwrap());

quote! {
Expand All @@ -186,8 +185,8 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
}
}
} else {
let args = gen.win32_args(&signature.params);
let params = gen.win32_params(&signature.params);
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);

quote! {
#doc
Expand All @@ -209,8 +208,8 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
}
}
SignatureKind::ReturnVoid => {
let args = gen.win32_args(&signature.params);
let params = gen.win32_params(&signature.params);
let args = gen.win32_args(&signature.params, kind);
let params = gen.win32_params(&signature.params, kind);
let does_not_return = does_not_return(gen, def);

quote! {
Expand Down
95 changes: 56 additions & 39 deletions crates/libs/bindgen/src/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -834,56 +834,73 @@ impl<'a> Gen<'a> {
quote! {}
}
}
pub fn win32_args(&self, params: &[SignatureParam]) -> TokenStream {
pub fn win32_args(&self, params: &[SignatureParam], kind: SignatureKind) -> TokenStream {
let mut tokens = quote! {};

for param in params {
let name = self.param_name(param.def);

if let ArrayInfo::Fixed(fixed) = param.array_info {
if fixed > 0 && self.reader.param_free_with(param.def).is_none() {
let signature = if self.reader.param_flags(param.def).output() {
quote! { ::core::mem::transmute(::windows::core::as_mut_ptr_or_null(#name)), }
} else {
quote! { ::core::mem::transmute(::windows::core::as_ptr_or_null(#name)), }
};

tokens.combine(&signature);
continue;
for (position, param) in params.iter().enumerate() {
match kind {
SignatureKind::Query(query) if query.object == position => {
tokens.combine(&quote! { &mut result__ as *mut _ as *mut _, });
}
}

if let ArrayInfo::RelativeLen(_) = param.array_info {
let signature = if self.reader.param_flags(param.def).output() {
quote! { ::core::mem::transmute(::windows::core::as_mut_ptr_or_null(#name)), }
} else {
quote! { ::core::mem::transmute(::windows::core::as_ptr_or_null(#name)), }
};

tokens.combine(&signature);
continue;
}

if let ArrayInfo::RelativePtr(relative) = param.array_info {
let name = self.param_name(params[relative].def);
tokens.combine(&quote! { #name.len() as _, });
continue;
}
SignatureKind::QueryOptional(query) if query.object == position => {
tokens.combine(&quote! { result__ as *mut _ as *mut _, });
}
SignatureKind::Query(query) | SignatureKind::QueryOptional(query) if query.guid == position => {
tokens.combine(&quote! { &<T as ::windows::core::Interface>::IID, });
}
_ => {
let name = self.param_name(param.def);
if let ArrayInfo::Fixed(fixed) = param.array_info {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of the chained if let ArrayInfo and continue calls you can turn this all into a match expression.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seem to be quite a few such candidates. I can tackle these separately.

if fixed > 0 && self.reader.param_free_with(param.def).is_none() {
let signature = if self.reader.param_flags(param.def).output() {
quote! { ::core::mem::transmute(::windows::core::as_mut_ptr_or_null(#name)), }
} else {
quote! { ::core::mem::transmute(::windows::core::as_ptr_or_null(#name)), }
};

tokens.combine(&signature);
continue;
}
}
if let ArrayInfo::RelativeLen(_) = param.array_info {
let signature = if self.reader.param_flags(param.def).output() {
quote! { ::core::mem::transmute(::windows::core::as_mut_ptr_or_null(#name)), }
} else {
quote! { ::core::mem::transmute(::windows::core::as_ptr_or_null(#name)), }
};

if self.reader.signature_param_is_convertible(param) {
tokens.combine(&quote! { #name.into_param().abi(), });
continue;
tokens.combine(&signature);
continue;
}
if let ArrayInfo::RelativePtr(relative) = param.array_info {
let name = self.param_name(params[relative].def);
tokens.combine(&quote! { #name.len() as _, });
continue;
}
if self.reader.signature_param_is_convertible(param) {
tokens.combine(&quote! { #name.into_param().abi(), });
continue;
}
tokens.combine(&quote! { ::core::mem::transmute(#name), });
}
}

tokens.combine(&quote! { ::core::mem::transmute(#name), });
}

tokens
}
pub fn win32_params(&self, params: &[SignatureParam]) -> TokenStream {
pub fn win32_params(&self, params: &[SignatureParam], kind: SignatureKind) -> TokenStream {
let mut tokens = quote! {};

for (position, param) in params.iter().enumerate() {
match kind {
SignatureKind::Query(query) | SignatureKind::QueryOptional(query) => {
if query.object == position || query.guid == position {
continue;
}
}
_ => {}
}

let name = self.param_name(param.def);

if let ArrayInfo::Fixed(fixed) = param.array_info {
Expand Down Expand Up @@ -973,7 +990,7 @@ impl<'a> Gen<'a> {

let return_type = match signature_kind {
SignatureKind::ReturnVoid => quote! {},
SignatureKind::Query | SignatureKind::QueryOptional | SignatureKind::ResultVoid => quote! { -> ::windows::core::Result<()> },
SignatureKind::Query(_) | SignatureKind::QueryOptional(_) | SignatureKind::ResultVoid => quote! { -> ::windows::core::Result<()> },
SignatureKind::ResultValue => {
let return_type = signature.params[signature.params.len() - 1].ty.deref();
let return_type = self.type_name(&return_type);
Expand Down
Loading