summaryrefslogtreecommitdiff
path: root/vendor/windows-interface
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
committermo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
commit8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch)
tree22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/windows-interface
parent4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff)
chore: add vendor directory
Diffstat (limited to 'vendor/windows-interface')
-rw-r--r--vendor/windows-interface/.cargo-checksum.json1
-rw-r--r--vendor/windows-interface/Cargo.lock47
-rw-r--r--vendor/windows-interface/Cargo.toml70
-rw-r--r--vendor/windows-interface/license-apache-2.0201
-rw-r--r--vendor/windows-interface/license-mit21
-rw-r--r--vendor/windows-interface/src/lib.rs762
6 files changed, 1102 insertions, 0 deletions
diff --git a/vendor/windows-interface/.cargo-checksum.json b/vendor/windows-interface/.cargo-checksum.json
new file mode 100644
index 00000000..8d2fc7fc
--- /dev/null
+++ b/vendor/windows-interface/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.lock":"71976eebe87246b69143413e859eaab13a93c42023ab2769de31c285e583bee6","Cargo.toml":"744f3033320d71ddbd8c260605dc161b856e29abcf4a7ea8751f2d5ffb1df75e","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","src/lib.rs":"f94cff0cfbb191170f6333c858e78eaaf1c51aae7f9b86b5cbb64c0d93d3bae3"},"package":"bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"} \ No newline at end of file
diff --git a/vendor/windows-interface/Cargo.lock b/vendor/windows-interface/Cargo.lock
new file mode 100644
index 00000000..9f8d116b
--- /dev/null
+++ b/vendor/windows-interface/Cargo.lock
@@ -0,0 +1,47 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "windows-interface"
+version = "0.59.1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/vendor/windows-interface/Cargo.toml b/vendor/windows-interface/Cargo.toml
new file mode 100644
index 00000000..997ef698
--- /dev/null
+++ b/vendor/windows-interface/Cargo.toml
@@ -0,0 +1,70 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.74"
+name = "windows-interface"
+version = "0.59.1"
+authors = ["Microsoft"]
+build = false
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "The interface macro for the windows crate"
+readme = false
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/microsoft/windows-rs"
+
+[package.metadata.docs.rs]
+default-target = "x86_64-pc-windows-msvc"
+targets = []
+
+[lib]
+name = "windows_interface"
+path = "src/lib.rs"
+proc-macro = true
+
+[dependencies.proc-macro2]
+version = "1.0"
+default-features = false
+
+[dependencies.quote]
+version = "1.0"
+default-features = false
+
+[dependencies.syn]
+version = "2.0"
+features = [
+ "parsing",
+ "proc-macro",
+ "printing",
+ "full",
+ "clone-impls",
+]
+default-features = false
+
+[dev-dependencies]
+
+[lints.rust]
+missing_docs = "warn"
+unsafe_op_in_unsafe_fn = "warn"
+
+[lints.rust.rust_2018_idioms]
+level = "warn"
+priority = -1
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+priority = 0
+check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"]
diff --git a/vendor/windows-interface/license-apache-2.0 b/vendor/windows-interface/license-apache-2.0
new file mode 100644
index 00000000..b5ed4ece
--- /dev/null
+++ b/vendor/windows-interface/license-apache-2.0
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright (c) Microsoft Corporation.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/windows-interface/license-mit b/vendor/windows-interface/license-mit
new file mode 100644
index 00000000..9e841e7a
--- /dev/null
+++ b/vendor/windows-interface/license-mit
@@ -0,0 +1,21 @@
+ MIT License
+
+ Copyright (c) Microsoft Corporation.
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE
diff --git a/vendor/windows-interface/src/lib.rs b/vendor/windows-interface/src/lib.rs
new file mode 100644
index 00000000..73c8f40c
--- /dev/null
+++ b/vendor/windows-interface/src/lib.rs
@@ -0,0 +1,762 @@
+//! Define COM interfaces to call or implement.
+//!
+//! Take a look at [macro@interface] for an example.
+//!
+//! Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs>
+
+use quote::quote;
+use syn::spanned::Spanned;
+
+/// Defines a COM interface to call or implement.
+///
+/// # Example
+/// ```rust,no_run
+/// use windows_core::*;
+///
+/// #[interface("094d70d6-5202-44b8-abb8-43860da5aca2")]
+/// unsafe trait IValue: IUnknown {
+/// fn GetValue(&self, value: *mut i32) -> HRESULT;
+/// }
+///
+/// #[implement(IValue)]
+/// struct Value(i32);
+///
+/// impl IValue_Impl for Value_Impl {
+/// unsafe fn GetValue(&self, value: *mut i32) -> HRESULT {
+/// *value = self.0;
+/// HRESULT(0)
+/// }
+/// }
+///
+/// let object: IValue = Value(123).into();
+/// // Call interface methods...
+/// ```
+#[proc_macro_attribute]
+pub fn interface(
+ attributes: proc_macro::TokenStream,
+ original_type: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+ let guid = syn::parse_macro_input!(attributes as Guid);
+ let interface = syn::parse_macro_input!(original_type as Interface);
+ let tokens = match interface.gen_tokens(&guid) {
+ Ok(t) => t,
+ Err(e) => return e.to_compile_error().into(),
+ };
+ tokens.into()
+}
+
+macro_rules! bail {
+ ($item:expr, $($msg:tt),*) => {
+ return Err(syn::Error::new($item.span(), std::fmt::format(format_args!($($msg),*))));
+ };
+
+}
+
+macro_rules! unexpected_token {
+ ($item:expr, $msg:expr) => {
+ if let Some(i) = $item {
+ bail!(i, "unexpected {}", $msg);
+ }
+ };
+}
+macro_rules! expected_token {
+ ($sig:tt.$item:tt(), $msg:expr) => {
+ if let None = $sig.$item() {
+ bail!($sig, "expected {}", $msg);
+ }
+ };
+}
+
+/// Parsed interface
+///
+/// ```rust,ignore
+/// #[windows_interface::interface("8CEEB155-2849-4ce5-9448-91FF70E1E4D9")]
+/// unsafe trait IUIAnimationVariable: IUnknown {
+/// //^ parses this
+/// fn GetValue(&self, value: *mut f64) -> HRESULT;
+/// }
+/// ```
+struct Interface {
+ visibility: syn::Visibility,
+ name: syn::Ident,
+ parent: Option<syn::Path>,
+ methods: Vec<InterfaceMethod>,
+ docs: Vec<syn::Attribute>,
+}
+
+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();
+
+ Ok(quote! {
+ #[repr(transparent)]
+ #(#docs)*
+ #vis struct #name(#parent);
+ #implementation
+ unsafe impl ::windows_core::Interface for #name {
+ type Vtable = #vtable_name;
+ const IID: ::windows_core::GUID = #guid;
+ }
+ impl ::windows_core::RuntimeName for #name {}
+ impl ::core::ops::Deref for #name {
+ type Target = #parent;
+ fn deref(&self) -> &Self::Target {
+ unsafe { ::core::mem::transmute(self) }
+ }
+ }
+ #com_trait
+ #vtable
+ #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;
+
+ if m.is_result() {
+ quote! {
+ #[inline(always)]
+ #vis unsafe fn #name<#(#generics),*>(&self, #(#params),*) #ret {
+ (::windows_core::Interface::vtable(self).#name)(::windows_core::Interface::as_raw(self), #(#args),*).ok()
+ }
+ }
+ } else {
+ quote! {
+ #[inline(always)]
+ #vis unsafe fn #name<#(#generics),*>(&self, #(#params),*) #ret {
+ (::windows_core::Interface::vtable(self).#name)(::windows_core::Interface::as_raw(self), #(#args),*)
+ }
+ }
+ }
+ })
+ .collect::<Vec<_>>();
+ quote! {
+ impl #name {
+ #(#methods)*
+ }
+ }
+ }
+
+ 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)*
+ unsafe fn #name(&self, #(#args),*) #ret;
+ }
+ })
+ .collect::<Vec<_>>();
+ let parent = self.parent_trait_constraint();
+
+ quote! {
+ #[allow(non_camel_case_types)]
+ #vis trait #name: Sized + #parent {
+ #(#methods)*
+ }
+ }
+ }
+
+ /// 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();
+
+ if m.is_result() {
+ quote! {
+ pub #name: unsafe extern "system" fn(this: *mut ::core::ffi::c_void, #(#args),*) -> ::windows_core::HRESULT,
+ }
+ } else {
+ quote! {
+ pub #name: unsafe extern "system" fn(this: *mut ::core::ffi::c_void, #(#args),*) #ret,
+ }
+ }
+ })
+ .collect::<Vec<_>>();
+
+ 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! {
+ unsafe extern "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! {
+ unsafe extern "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 *const Impl;
+ (*this).#name(#(#params),*).into()
+ }
+ }
+ }
+ })
+ .collect::<Vec<_>>();
+
+ if let Some(parent_vtable) = parent_vtable {
+ let entries = self
+ .methods
+ .iter()
+ .map(|m| {
+ let name = &m.name;
+ quote!(#name: #name::<Identity, OFFSET>)
+ })
+ .collect::<Vec<_>>();
+
+ quote! {
+ #[repr(C)]
+ #[doc(hidden)]
+ #vis struct #vtable_name {
+ pub base__: #parent_vtable,
+ #(#vtable_entries)*
+ }
+ impl #vtable_name {
+ pub const fn new<
+ Identity: ::windows_core::IUnknownImpl,
+ const OFFSET: isize,
+ >() -> Self
+ where
+ Identity : #trait_name
+ {
+ #(#functions)*
+ Self { base__: #parent_vtable::new::<#parent_vtable_generics>(), #(#entries),* }
+ }
+
+ #[inline(always)]
+ pub fn matches(iid: &::windows_core::GUID) -> bool {
+ *iid == <#name as ::windows_core::Interface>::IID
+ #or_parent_matches
+ }
+ }
+ }
+ } else {
+ let entries = self
+ .methods
+ .iter()
+ .map(|m| {
+ let name = &m.name;
+ quote!(#name: #name::<Impl>)
+ })
+ .collect::<Vec<_>>();
+
+ quote! {
+ #[repr(C)]
+ #[doc(hidden)]
+ #vis struct #vtable_name {
+ #(#vtable_entries)*
+ }
+ impl #vtable_name {
+ pub const fn new<Impl: #trait_name>() -> Self {
+ #(#functions)*
+ Self { #(#entries),* }
+ }
+ }
+ struct #implvtbl_name<T: #trait_name> (::core::marker::PhantomData<T>);
+ impl<T: #trait_name> #implvtbl_name<T> {
+ const VTABLE: #vtable_name = #vtable_name::new::<T>();
+ }
+ impl #name {
+ fn new<'a, T: #trait_name>(this: &'a T) -> ::windows_core::ScopedInterface<'a, #name> {
+ let this = ::windows_core::ScopedHeap { vtable: &#implvtbl_name::<T>::VTABLE as *const _ as *const _, this: this as *const _ as *const _ };
+ let this = ::core::mem::ManuallyDrop::new(::windows_core::imp::Box::new(this));
+ unsafe { ::windows_core::ScopedInterface::new(::core::mem::transmute(&this.vtable)) }
+ }
+ }
+ }
+ }
+ }
+
+ /// Generates various conversions such as from and to `IUnknown`
+ fn gen_conversions(&self) -> proc_macro2::TokenStream {
+ let name = &self.name;
+ let name_string = format!("{name}");
+ quote! {
+ impl ::core::convert::From<#name> for ::windows_core::IUnknown {
+ fn from(value: #name) -> Self {
+ unsafe { ::core::mem::transmute(value) }
+ }
+ }
+ impl ::core::convert::From<&#name> for ::windows_core::IUnknown {
+ fn from(value: &#name) -> Self {
+ ::core::convert::From::from(::core::clone::Clone::clone(value))
+ }
+ }
+ impl ::core::clone::Clone for #name {
+ fn clone(&self) -> Self {
+ Self(self.0.clone())
+ }
+ }
+ impl ::core::cmp::PartialEq for #name {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+ }
+ impl ::core::cmp::Eq for #name {}
+ impl ::core::fmt::Debug for #name {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
+ f.debug_tuple(#name_string).field(&::windows_core::Interface::as_raw(self)).finish()
+ }
+ }
+ }
+ }
+
+ fn parent_type(&self) -> proc_macro2::TokenStream {
+ if let Some(parent) = &self.parent {
+ quote!(#parent)
+ } else {
+ quote!(::core::ptr::NonNull<::core::ffi::c_void>)
+ }
+ }
+
+ fn parent_vtable(&self) -> Option<proc_macro2::TokenStream> {
+ if let Some((ident, path)) = self.parent_path().split_last() {
+ let ident = quote::format_ident!("{}_Vtbl", ident);
+ Some(quote! { #(#path::)* #ident })
+ } else {
+ None
+ }
+ }
+
+ fn parent_is_iunknown(&self) -> bool {
+ if let Some(ident) = self.parent_path().last() {
+ ident == "IUnknown"
+ } else {
+ false
+ }
+ }
+
+ fn parent_path(&self) -> Vec<syn::Ident> {
+ if let Some(parent) = &self.parent {
+ parent
+ .segments
+ .iter()
+ .map(|segment| segment.ident.clone())
+ .collect()
+ } else {
+ vec![]
+ }
+ }
+
+ /// Gets the parent trait constraint which is nothing if the parent is IUnknown
+ fn parent_trait_constraint(&self) -> proc_macro2::TokenStream {
+ if let Some((ident, path)) = self.parent_path().split_last() {
+ if ident != "IUnknown" {
+ let ident = quote::format_ident!("{}_Impl", ident);
+ return quote! { #(#path::)* #ident };
+ }
+ }
+
+ quote! {}
+ }
+}
+
+impl syn::parse::Parse for Interface {
+ fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
+ let attributes = input.call(syn::Attribute::parse_outer)?;
+ let mut docs = Vec::new();
+ for attr in attributes.into_iter() {
+ let path = attr.path();
+ if path.is_ident("doc") {
+ docs.push(attr);
+ } else {
+ return Err(syn::Error::new(path.span(), "Unrecognized attribute "));
+ }
+ }
+
+ let visibility = input.parse::<syn::Visibility>()?;
+ _ = input.parse::<syn::Token![unsafe]>()?;
+ _ = input.parse::<syn::Token![trait]>()?;
+ let name = input.parse::<syn::Ident>()?;
+ _ = input.parse::<syn::Token![:]>();
+ let parent = input.parse::<syn::Path>().ok();
+ let content;
+ syn::braced!(content in input);
+ let mut methods = Vec::new();
+ while !content.is_empty() {
+ methods.push(content.parse::<InterfaceMethod>()?);
+ }
+ Ok(Self {
+ visibility,
+ methods,
+ name,
+ parent,
+ docs,
+ })
+ }
+}
+
+/// Parsed interface guid attribute
+///
+/// ```rust,ignore
+/// #[windows_interface::interface("8CEEB155-2849-4ce5-9448-91FF70E1E4D9")]
+/// //^ parses this
+/// unsafe trait IUIAnimationVariable: IUnknown {
+/// fn GetValue(&self, value: *mut f64) -> HRESULT;
+/// }
+/// ```
+struct Guid(Option<syn::LitStr>);
+
+impl Guid {
+ fn to_tokens(&self) -> syn::Result<proc_macro2::TokenStream> {
+ fn hex_lit(num: &str) -> syn::LitInt {
+ syn::LitInt::new(&format!("0x{num}"), proc_macro2::Span::call_site())
+ }
+
+ 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()
+ ),
+ ));
+ }
+
+ Ok(part.to_owned())
+ }
+
+ if let Some(value) = &self.0 {
+ let guid_value = value.value();
+ let mut delimited = guid_value.split('-').fuse();
+ let chunks = [
+ ensure_length(delimited.next(), 0, 8, value.span())?,
+ ensure_length(delimited.next(), 1, 4, value.span())?,
+ ensure_length(delimited.next(), 2, 4, value.span())?,
+ ensure_length(delimited.next(), 3, 4, value.span())?,
+ ensure_length(delimited.next(), 4, 12, value.span())?,
+ ];
+
+ 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);
+
+ let (data4_7, data4_8) = rest.split_at(2);
+ let data4_7 = hex_lit(data4_7);
+ let data4_8 = hex_lit(data4_8);
+ Ok(quote! {
+ ::windows_core::GUID {
+ data1: #data1,
+ data2: #data2,
+ data3: #data3,
+ data4: [#data4_1, #data4_2, #data4_3, #data4_4, #data4_5, #data4_6, #data4_7, #data4_8]
+ }
+ })
+ } else {
+ Ok(quote! {
+ ::windows_core::GUID::zeroed()
+ })
+ }
+ }
+}
+
+impl syn::parse::Parse for Guid {
+ fn parse(cursor: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
+ let string: Option<syn::LitStr> = cursor.parse().ok();
+
+ Ok(Self(string))
+ }
+}
+
+/// A parsed interface method
+///
+/// ```rust,ignore
+/// #[windows_interface::interface("8CEEB155-2849-4ce5-9448-91FF70E1E4D9")]
+/// unsafe trait IUIAnimationVariable: IUnknown {
+/// fn GetValue(&self, value: *mut f64) -> HRESULT;
+/// //^ parses this
+/// }
+/// ```
+struct InterfaceMethod {
+ pub name: syn::Ident,
+ pub visibility: syn::Visibility,
+ pub args: Vec<InterfaceMethodArg>,
+ pub ret: syn::ReturnType,
+ pub docs: Vec<syn::Attribute>,
+}
+
+impl InterfaceMethod {
+ fn is_result(&self) -> bool {
+ if let syn::ReturnType::Type(_, ty) = &self.ret {
+ if let syn::Type::Path(path) = &**ty {
+ if let Some(segment) = path.path.segments.last() {
+ let ident = segment.ident.to_string();
+ if ident == "Result" {
+ if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
+ if args.args.len() == 1 {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ false
+ }
+
+ /// Generates arguments (of the form `$pat: $type`)
+ fn gen_args(&self) -> Vec<proc_macro2::TokenStream> {
+ self.args
+ .iter()
+ .map(|a| {
+ let pat = &a.pat;
+ let ty = &a.ty;
+ quote! { #pat: #ty }
+ })
+ .collect::<Vec<_>>()
+ }
+
+ fn gen_consume_generics(&self) -> Vec<proc_macro2::TokenStream> {
+ self.args
+ .iter()
+ .enumerate()
+ .filter_map(|(generic_index, a)| {
+ if let Some((ty, ident)) = a.borrow_type() {
+ let generic_ident = quote::format_ident!("P{generic_index}");
+ if ident == "Ref" {
+ Some(quote! { #generic_ident: ::windows_core::Param<#ty> })
+ } else {
+ Some(quote! { #generic_ident: ::windows_core::OutParam<#ty> })
+ }
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>()
+ }
+
+ fn gen_consume_params(&self) -> Vec<proc_macro2::TokenStream> {
+ self.args
+ .iter()
+ .enumerate()
+ .map(|(generic_index, a)| {
+ let pat = &a.pat;
+
+ if a.borrow_type().is_some() {
+ let generic_ident = quote::format_ident!("P{generic_index}");
+ quote! { #pat: #generic_ident }
+ } else {
+ let ty = &a.ty;
+ quote! { #pat: #ty }
+ }
+ })
+ .collect::<Vec<_>>()
+ }
+
+ fn gen_consume_args(&self) -> Vec<proc_macro2::TokenStream> {
+ self.args
+ .iter()
+ .map(|a| {
+ let pat = &a.pat;
+
+ if let Some((_, ident)) = a.borrow_type() {
+ if ident == "Ref" {
+ quote! { #pat.param().borrow() }
+ } else {
+ quote! { #pat.borrow_mut() }
+ }
+ } else {
+ quote! { #pat }
+ }
+ })
+ .collect::<Vec<_>>()
+ }
+}
+
+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>,
+}
+
+impl InterfaceMethodArg {
+ fn borrow_type(&self) -> Option<(syn::Type, String)> {
+ if let syn::Type::Path(path) = &*self.ty {
+ if let Some(segment) = path.path.segments.last() {
+ let ident = segment.ident.to_string();
+ if matches!(ident.as_str(), "Ref" | "OutRef") {
+ if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
+ if args.args.len() == 1 {
+ if let Some(syn::GenericArgument::Type(ty)) = args.args.first() {
+ return Some((ty.clone(), ident));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ None
+ }
+}