Skip to content

Commit

Permalink
Transform NTSTATUS functions into Result<()> (#994)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr committed Jul 22, 2021
1 parent 7455af8 commit cef626a
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 23 deletions.
67 changes: 44 additions & 23 deletions crates/gen/src/types/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,36 +108,57 @@ impl Function {
}
}
} else if let Some(return_type) = &signature.return_type {
if return_type.kind == ElementType::HRESULT {
quote! {
pub unsafe fn #name<#constraints>(#params) -> ::windows::Result<()> {
#[cfg(windows)]
{
#link_attr
extern "system" {
fn #name(#(#abi_params),*) -> ::windows::HRESULT;
match &return_type.kind {
ElementType::HRESULT => {
quote! {
pub unsafe fn #name<#constraints>(#params) -> ::windows::Result<()> {
#[cfg(windows)]
{
#link_attr
extern "system" {
fn #name(#(#abi_params),*) -> ::windows::HRESULT;
}
#name(#(#args),*).ok()
}
#name(#(#args),*).ok()
#[cfg(not(windows))]
unimplemented!("Unsupported target OS");
}
#[cfg(not(windows))]
unimplemented!("Unsupported target OS");
}
}
} else {
let return_type = return_type.gen_win32(gen);
ElementType::TypeDef(def)
if def.full_name() == ("Windows.Win32.Foundation", "NTSTATUS") =>
{
quote! {
pub unsafe fn #name<#constraints>(#params) -> ::windows::Result<()> {
#[cfg(windows)]
{
#link_attr
extern "system" {
fn #name(#(#abi_params),*) #abi_return_type;
}
#name(#(#args),*).ok()
}
#[cfg(not(windows))]
unimplemented!("Unsupported target OS");
}
}
}
_ => {
let return_type = return_type.gen_win32(gen);

quote! {
pub unsafe fn #name<#constraints>(#params) -> #return_type {
#[cfg(windows)]
{
#link_attr
extern "system" {
fn #name(#(#abi_params),*) #abi_return_type;
quote! {
pub unsafe fn #name<#constraints>(#params) -> #return_type {
#[cfg(windows)]
{
#link_attr
extern "system" {
fn #name(#(#abi_params),*) #abi_return_type;
}
#name(#(#args),*)
}
#name(#(#args),*)
#[cfg(not(windows))]
unimplemented!("Unsupported target OS");
}
#[cfg(not(windows))]
unimplemented!("Unsupported target OS");
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/gen/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod handle;
mod interface;
mod matrix3x2;
mod matrix4x4;
mod ntstatus;
mod pstr;
mod pwstr;
mod r#struct;
Expand All @@ -33,6 +34,7 @@ pub use handle::*;
pub use interface::*;
pub use matrix3x2::*;
pub use matrix4x4::*;
pub use ntstatus::*;
pub use pstr::*;
pub use pwstr::*;
pub use r#enum::*;
Expand Down
34 changes: 34 additions & 0 deletions crates/gen/src/types/ntstatus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use super::*;

pub fn gen_ntstatus() -> TokenStream {
quote! {
#[repr(transparent)]
#[derive(::std::default::Default, ::std::clone::Clone, ::std::marker::Copy, ::std::cmp::PartialEq, ::std::cmp::Eq, ::std::fmt::Debug)]
pub struct NTSTATUS(pub u32);

impl NTSTATUS {
#[inline]
pub const fn is_ok(self) -> bool {
self.0 == 0
}

#[inline]
pub const fn is_err(self) -> bool {
!self.is_ok()
}

#[inline]
pub fn ok(self) -> ::windows::Result<()> {
if self.is_ok() {
Ok(())
} else {
Err(::windows::Error::fast_error(::windows::HRESULT(self.0 | 0x10000000)))
}
}
}

unsafe impl ::windows::Abi for NTSTATUS {
type Abi = Self;
}
}
}
1 change: 1 addition & 0 deletions crates/gen/src/types/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ impl Struct {
("Windows.Win32.Foundation", "PWSTR") => Some(gen_pwstr()),
("Windows.Win32.Foundation", "PSTR") => Some(gen_pstr()),
("Windows.Win32.Foundation", "BSTR") => Some(gen_bstr()),
("Windows.Win32.Foundation", "NTSTATUS") => Some(gen_ntstatus()),
_ => None,
}
}
Expand Down
11 changes: 11 additions & 0 deletions tests/ntstatus/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "test_ntstatus"
version = "0.0.0"
authors = ["Microsoft"]
edition = "2018"

[dependencies]
windows = { path = "../.." }

[build-dependencies]
windows = { path = "../.." }
8 changes: 8 additions & 0 deletions tests/ntstatus/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fn main() {
windows::build! {
Windows::Win32::Foundation::STATUS_NOT_FOUND,
Windows::Win32::Security::Cryptography::Core::{
BCryptGenRandom, BCryptOpenAlgorithmProvider,
},
};
}
1 change: 1 addition & 0 deletions tests/ntstatus/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
windows::include_bindings!();
42 changes: 42 additions & 0 deletions tests/ntstatus/tests/ntstatus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use test_ntstatus::{
Windows::Win32::Foundation::{NTSTATUS, STATUS_NOT_FOUND},
Windows::Win32::Security::Cryptography::Core::{BCryptGenRandom, BCryptOpenAlgorithmProvider},
};

use windows::{Guid, Result, HRESULT};

#[test]
fn test() -> Result<()> {
let status = NTSTATUS::default();
assert_eq!(status.0, 0);
assert_eq!(status.is_ok(), true);
assert_eq!(status.is_err(), false);
assert_eq!(status.ok().is_ok(), true);

let status = STATUS_NOT_FOUND;
assert_eq!(status.0, 0xC000_0225);
assert_eq!(status.is_ok(), false);
assert_eq!(status.is_err(), true);
assert_eq!(status.ok().is_ok(), false);

let error = status.ok().unwrap_err();
assert_eq!(error.code(), HRESULT(0xD000_0225));

unsafe {
let mut provider = std::ptr::null_mut();
BCryptOpenAlgorithmProvider(&mut provider, "RNG", None, Default::default())?;

let mut random = Guid::zeroed();

BCryptGenRandom(
provider,
&mut random as *mut _ as _,
std::mem::size_of::<Guid>() as _,
0,
)?;

assert_ne!(random, Guid::zeroed());
}

Ok(())
}

0 comments on commit cef626a

Please sign in to comment.