Skip to content

Commit

Permalink
Merge branch 'master' into rafael/compid
Browse files Browse the repository at this point in the history
  • Loading branch information
riverar committed Sep 18, 2023
2 parents 7970f7b + 41d2587 commit d846498
Show file tree
Hide file tree
Showing 841 changed files with 34,516 additions and 219,815 deletions.
2 changes: 1 addition & 1 deletion crates/libs/bindgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ rust-version = "1.56"
license = "MIT OR Apache-2.0"
description = "Windows metadata compiler"
repository = "https://github.com/microsoft/windows-rs"
readme = "../../../docs/readme.md"
readme = "readme.md"

[package.metadata.docs.rs]
default-target = "x86_64-pc-windows-msvc"
Expand Down
88 changes: 88 additions & 0 deletions crates/libs/bindgen/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
## Rust for Windows

The [windows](https://crates.io/crates/windows) and [windows-sys](https://crates.io/crates/windows-sys) crates let you call any Windows API past, present, and future using code generated on the fly directly from the [metadata describing the API](https://github.com/microsoft/windows-rs/tree/master/crates/libs/bindgen/default) and right into your Rust package where you can call them as if they were just another Rust module. The Rust language projection follows in the tradition established by [C++/WinRT](https://github.com/microsoft/cppwinrt) of building language projections for Windows using standard languages and compilers, providing a natural and idiomatic way for Rust developers to call Windows APIs.

* [Getting started](https://kennykerr.ca/rust-getting-started/)
* [Samples](https://github.com/microsoft/windows-rs/tree/0.52.0/crates/samples) <!-- link to samples for upcoming release -->
* [Releases](https://github.com/microsoft/windows-rs/releases)

Start by adding the following to your Cargo.toml file:

```toml
[dependencies.windows]
version = "0.52"
features = [
"Data_Xml_Dom",
"Win32_Foundation",
"Win32_Security",
"Win32_System_Threading",
"Win32_UI_WindowsAndMessaging",
]
```

Make use of any Windows APIs as needed:

```rust,no_run
use windows::{
core::*, Data::Xml::Dom::*, Win32::Foundation::*, Win32::System::Threading::*,
Win32::UI::WindowsAndMessaging::*,
};
fn main() -> Result<()> {
let doc = XmlDocument::new()?;
doc.LoadXml(h!("<html>hello world</html>"))?;
let root = doc.DocumentElement()?;
assert!(root.NodeName()? == "html");
assert!(root.InnerText()? == "hello world");
unsafe {
let event = CreateEventW(None, true, false, None)?;
SetEvent(event)?;
WaitForSingleObject(event, 0);
CloseHandle(event)?;
MessageBoxA(None, s!("Ansi"), s!("Caption"), MB_OK);
MessageBoxW(None, w!("Wide"), w!("Caption"), MB_OK);
}
Ok(())
}
```

## windows-sys

The `windows-sys` crate is a zero-overhead fallback for the most demanding situations and primarily where the absolute best compile time is essential. It only includes function declarations (externs), structs, and constants. No convenience helpers, traits, or wrappers are provided.

Start by adding the following to your Cargo.toml file:

```toml
[dependencies.windows-sys]
version = "0.52"
features = [
"Win32_Foundation",
"Win32_Security",
"Win32_System_Threading",
"Win32_UI_WindowsAndMessaging",
]
```

Make use of any Windows APIs as needed:

```rust,no_run
use windows_sys::{
core::*, Win32::Foundation::*, Win32::System::Threading::*, Win32::UI::WindowsAndMessaging::*,
};
fn main() {
unsafe {
let event = CreateEventW(std::ptr::null(), 1, 0, std::ptr::null());
SetEvent(event);
WaitForSingleObject(event, 0);
CloseHandle(event);
MessageBoxA(0, s!("Ansi"), s!("Caption"), MB_OK);
MessageBoxW(0, w!("Wide"), w!("Caption"), MB_OK);
}
}
```
8 changes: 0 additions & 8 deletions crates/libs/bindgen/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,4 @@ impl Error {
pub(crate) fn with_path(self, path: &str) -> Self {
Self { path: path.to_string(), ..self }
}

// pub(crate) fn with_span(self, span: proc_macro2::Span) -> Self {
// let start = span.start();
// Self {
// span: Some((start.line, start.column)),
// ..self
// }
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,6 @@ fn param_or_enum(reader: &Reader, row: Param) -> Option<String> {
})
}

pub fn signature_param_is_borrowed(reader: &Reader, param: &SignatureParam) -> bool {
type_is_borrowed(reader, &param.ty)
}

pub fn signature_param_is_convertible(reader: &Reader, param: &SignatureParam) -> bool {
!reader.param_flags(param.def).contains(ParamAttributes::Out) && !param.ty.is_winrt_array() && !param.ty.is_pointer() && !param.kind.is_array() && (type_is_borrowed(reader, &param.ty) || type_is_non_exclusive_winrt_interface(reader, &param.ty) || type_is_trivially_convertible(reader, &param.ty))
}
Expand Down Expand Up @@ -268,7 +264,10 @@ fn signature_param_is_retval(reader: &Reader, param: &SignatureParam) -> bool {
}
// Win32 callbacks are defined as `Option<T>` so we don't include them here to avoid
// producing the `Result<Option<T>>` anti-pattern.
!type_is_callback(reader, &param.ty.deref())
match param.ty.deref() {
Type::TypeDef(def, _) => !type_def_is_callback(reader, def),
_ => true,
}
}

pub fn signature_kind(reader: &Reader, signature: &Signature) -> SignatureKind {
Expand All @@ -280,13 +279,11 @@ pub fn signature_kind(reader: &Reader, signature: &Signature) -> SignatureKind {
Type::Void => SignatureKind::ReturnVoid,
Type::HRESULT => {
if signature.params.len() >= 2 {
if let Some(guid) = signature_param_is_query_guid(reader, &signature.params) {
if let Some(object) = signature_param_is_query_object(reader, &signature.params) {
if reader.param_flags(signature.params[object].def).contains(ParamAttributes::Optional) {
return SignatureKind::QueryOptional(QueryPosition { object, guid });
} else {
return SignatureKind::Query(QueryPosition { object, guid });
}
if let Some((guid, object)) = signature_param_is_query(reader, &signature.params) {
if reader.param_flags(signature.params[object].def).contains(ParamAttributes::Optional) {
return SignatureKind::QueryOptional(QueryPosition { object, guid });
} else {
return SignatureKind::Query(QueryPosition { object, guid });
}
}
}
Expand All @@ -296,7 +293,6 @@ pub fn signature_kind(reader: &Reader, signature: &Signature) -> SignatureKind {
SignatureKind::ResultVoid
}
}
Type::TypeDef(def, _) if reader.type_def_type_name(*def) == TypeName::NTSTATUS => SignatureKind::ResultVoid,
Type::TypeDef(def, _) if reader.type_def_type_name(*def) == TypeName::WIN32_ERROR => SignatureKind::ResultVoid,
Type::TypeDef(def, _) if reader.type_def_type_name(*def) == TypeName::BOOL && method_def_last_error(reader, signature.def) => SignatureKind::ResultVoid,
_ if type_is_struct(reader, &signature.return_type) => SignatureKind::ReturnStruct,
Expand All @@ -312,12 +308,14 @@ fn signature_is_retval(reader: &Reader, signature: &Signature) -> bool {
})
}

fn signature_param_is_query_guid(reader: &Reader, params: &[SignatureParam]) -> Option<usize> {
params.iter().rposition(|param| param.ty == Type::ConstPtr(Box::new(Type::GUID), 1) && !reader.param_flags(param.def).contains(ParamAttributes::Out))
}
fn signature_param_is_query(reader: &Reader, params: &[SignatureParam]) -> Option<(usize, usize)> {
if let Some(guid) = params.iter().rposition(|param| param.ty == Type::ConstPtr(Box::new(Type::GUID), 1) && !reader.param_flags(param.def).contains(ParamAttributes::Out)) {
if let Some(object) = params.iter().rposition(|param| param.ty == Type::MutPtr(Box::new(Type::Void), 2) && reader.has_attribute(param.def, "ComOutPtrAttribute")) {
return Some((guid, object));
}
}

fn signature_param_is_query_object(reader: &Reader, params: &[SignatureParam]) -> Option<usize> {
params.iter().rposition(|param| param.ty == Type::MutPtr(Box::new(Type::Void), 2) && reader.has_attribute(param.def, "ComOutPtrAttribute"))
None
}

fn method_def_last_error(reader: &Reader, row: MethodDef) -> bool {
Expand All @@ -328,7 +326,7 @@ fn method_def_last_error(reader: &Reader, row: MethodDef) -> bool {
}
}

fn type_is_borrowed(reader: &Reader, ty: &Type) -> bool {
pub fn type_is_borrowed(reader: &Reader, ty: &Type) -> bool {
match ty {
Type::TypeDef(row, _) => !type_def_is_blittable(reader, *row),
Type::BSTR | Type::PCSTR | Type::PCWSTR | Type::IInspectable | Type::IUnknown | Type::GenericParam(_) => true,
Expand Down Expand Up @@ -360,14 +358,6 @@ fn type_is_trivially_convertible(reader: &Reader, ty: &Type) -> bool {
TypeKind::Struct => type_def_is_handle(reader, *row),
_ => false,
},
Type::PCSTR | Type::PCWSTR => true,
_ => false,
}
}

fn type_is_callback(reader: &Reader, ty: &Type) -> bool {
match ty {
Type::TypeDef(row, _) => type_def_is_callback(reader, *row),
_ => false,
}
}
Expand Down Expand Up @@ -479,16 +469,6 @@ fn type_name<'a>(reader: &Reader<'a>, ty: &Type) -> &'a str {
}
}

pub fn type_def_async_kind(reader: &Reader, row: TypeDef) -> AsyncKind {
match reader.type_def_type_name(row) {
TypeName::IAsyncAction => AsyncKind::Action,
TypeName::IAsyncActionWithProgress => AsyncKind::ActionWithProgress,
TypeName::IAsyncOperation => AsyncKind::Operation,
TypeName::IAsyncOperationWithProgress => AsyncKind::OperationWithProgress,
_ => AsyncKind::None,
}
}

pub fn field_is_blittable(reader: &Reader, row: Field, enclosing: TypeDef) -> bool {
type_is_blittable(reader, &reader.field_type(row, Some(enclosing)))
}
Expand All @@ -497,14 +477,6 @@ pub fn field_is_copyable(reader: &Reader, row: Field, enclosing: TypeDef) -> boo
type_is_copyable(reader, &reader.field_type(row, Some(enclosing)))
}

pub fn field_guid(reader: &Reader, row: Field) -> Option<GUID> {
reader.find_attribute(row, "GuidAttribute").map(|attribute| GUID::from_args(&reader.attribute_args(attribute)))
}

pub fn field_is_ansi(reader: &Reader, row: Field) -> bool {
reader.find_attribute(row, "NativeEncodingAttribute").is_some_and(|attribute| matches!(reader.attribute_args(attribute).get(0), Some((_, Value::String(encoding))) if encoding == "ansi"))
}

pub fn type_is_blittable(reader: &Reader, ty: &Type) -> bool {
match ty {
Type::TypeDef(row, _) => type_def_is_blittable(reader, *row),
Expand Down Expand Up @@ -549,83 +521,10 @@ pub fn type_def_is_copyable(reader: &Reader, row: TypeDef) -> bool {
}
}

pub fn method_def_special_name(reader: &Reader, row: MethodDef) -> String {
let name = reader.method_def_name(row);
if reader.method_def_flags(row).contains(MethodAttributes::SpecialName) {
if name.starts_with("get") {
name[4..].to_string()
} else if name.starts_with("put") {
format!("Set{}", &name[4..])
} else if name.starts_with("add") {
name[4..].to_string()
} else if name.starts_with("remove") {
format!("Remove{}", &name[7..])
} else {
name.to_string()
}
} else {
if let Some(attribute) = reader.find_attribute(row, "OverloadAttribute") {
for (_, arg) in reader.attribute_args(attribute) {
if let Value::String(name) = arg {
return name;
}
}
}
name.to_string()
}
}

pub fn method_def_static_lib(reader: &Reader, row: MethodDef) -> Option<String> {
reader.find_attribute(row, "StaticLibraryAttribute").and_then(|attribute| {
let args = reader.attribute_args(attribute);
if let Value::String(value) = &args[0].1 {
return Some(value.clone());
}
None
})
}

pub fn method_def_extern_abi(reader: &Reader, def: MethodDef) -> &'static str {
let impl_map = reader.method_def_impl_map(def).expect("ImplMap not found");
let flags = reader.impl_map_flags(impl_map);

if flags.contains(PInvokeAttributes::CallConvPlatformapi) {
"system"
} else if flags.contains(PInvokeAttributes::CallConvCdecl) {
"cdecl"
} else {
unimplemented!()
}
}

pub fn type_def_has_default_constructor(reader: &Reader, row: TypeDef) -> bool {
for attribute in reader.attributes(row) {
if reader.attribute_name(attribute) == "ActivatableAttribute" {
if reader.attribute_args(attribute).iter().any(|arg| matches!(arg.1, Value::TypeName(_))) {
continue;
} else {
return true;
}
}
}
false
}

pub fn type_def_has_default_interface(reader: &Reader, row: TypeDef) -> bool {
reader.type_def_interface_impls(row).any(|imp| reader.has_attribute(imp, "DefaultAttribute"))
}

pub fn type_def_is_exclusive(reader: &Reader, row: TypeDef) -> bool {
reader.has_attribute(row, "ExclusiveToAttribute")
}

pub fn type_is_exclusive(reader: &Reader, ty: &Type) -> bool {
match ty {
Type::TypeDef(row, _) => type_def_is_exclusive(reader, *row),
_ => false,
}
}

pub fn type_is_struct(reader: &Reader, ty: &Type) -> bool {
// This check is used to detect virtual functions that return C-style PODs that affect how the stack is packed for x86.
// It could be defined as a struct with more than one field but that check is complicated as it would have to detect
Expand Down Expand Up @@ -800,14 +699,6 @@ pub fn type_def_is_handle(reader: &Reader, row: TypeDef) -> bool {
reader.has_attribute(row, "NativeTypedefAttribute")
}

pub fn type_has_replacement(reader: &Reader, ty: &Type) -> bool {
match ty {
Type::HRESULT | Type::PCSTR | Type::PCWSTR => true,
Type::TypeDef(row, _) => type_def_is_handle(reader, *row) || reader.type_def_kind(*row) == TypeKind::Enum,
_ => false,
}
}

pub fn type_def_guid(reader: &Reader, row: TypeDef) -> Option<GUID> {
reader.find_attribute(row, "GuidAttribute").map(|attribute| GUID::from_args(&reader.attribute_args(attribute)))
}
Expand All @@ -826,23 +717,6 @@ pub fn type_def_bases(reader: &Reader, mut row: TypeDef) -> Vec<TypeDef> {
bases
}

pub fn type_def_is_agile(reader: &Reader, row: TypeDef) -> bool {
for attribute in reader.attributes(row) {
match reader.attribute_name(attribute) {
"AgileAttribute" => return true,
"MarshalingBehaviorAttribute" => {
if let Some((_, Value::EnumDef(_, value))) = reader.attribute_args(attribute).get(0) {
if let Value::I32(2) = **value {
return true;
}
}
}
_ => {}
}
}
matches!(reader.type_def_type_name(row), TypeName::IAsyncAction | TypeName::IAsyncActionWithProgress | TypeName::IAsyncOperation | TypeName::IAsyncOperationWithProgress)
}

pub fn type_def_invalid_values(reader: &Reader, row: TypeDef) -> Vec<i64> {
let mut values = Vec::new();
for attribute in reader.attributes(row) {
Expand All @@ -855,15 +729,6 @@ pub fn type_def_invalid_values(reader: &Reader, row: TypeDef) -> Vec<i64> {
values
}

pub fn type_def_usable_for(reader: &Reader, row: TypeDef) -> Option<TypeDef> {
if let Some(attribute) = reader.find_attribute(row, "AlsoUsableForAttribute") {
if let Some((_, Value::String(name))) = reader.attribute_args(attribute).get(0) {
return reader.get_type_def(TypeName::new(reader.type_def_namespace(row), name.as_str())).next();
}
}
None
}

fn type_def_is_nullable(reader: &Reader, row: TypeDef) -> bool {
match reader.type_def_kind(row) {
TypeKind::Interface | TypeKind::Class => true,
Expand Down Expand Up @@ -916,11 +781,3 @@ pub fn type_def_vtables(reader: &Reader, row: TypeDef) -> Vec<Type> {
pub fn type_def_interfaces<'a>(reader: &'a Reader<'a>, row: TypeDef, generics: &'a [Type]) -> impl Iterator<Item = Type> + 'a {
reader.type_def_interface_impls(row).map(move |row| reader.interface_impl_type(row, generics))
}

pub fn type_underlying_type(reader: &Reader, ty: &Type) -> Type {
match ty {
Type::TypeDef(row, _) => reader.type_def_underlying_type(*row),
Type::HRESULT => Type::I32,
_ => ty.clone(),
}
}
Loading

0 comments on commit d846498

Please sign in to comment.