Skip to content

Commit

Permalink
Merge pull request #25 from Boddlnagg/error-handling
Browse files Browse the repository at this point in the history
Improve error handling
  • Loading branch information
Boddlnagg authored Sep 2, 2016
2 parents ce6616e + 309f94f commit a7ee7de
Show file tree
Hide file tree
Showing 10 changed files with 12,501 additions and 12,392 deletions.
6 changes: 3 additions & 3 deletions Generator/Types/MethodDef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,16 +220,16 @@ public string GetWrapperDefinition()

string inline = isGetMany ? "" : "#[inline] ";

return inline + "pub unsafe fn " + name + "(" + String.Join(", ", inputParameters) + ") -> RtResult<" + outType + @"> {" + outInit + @"
return inline + "pub unsafe fn " + name + "(" + String.Join(", ", inputParameters) + ") -> Result<" + outType + @"> {" + outInit + @"
let hr = ((*self.lpVtbl)." + rawName + ")(" + String.Join(", ", rawParams) + ");" + @"
if hr == ::w::S_OK { " + outWrap + @" } else { Err(hr) }
if hr == S_OK { " + outWrap + @" } else { err(hr) }
}";
}

public string GetRawDeclaration()
{
var name = GetRawName();
return "fn " + name + "(" + String.Join(", ", GetParameterDeclarations()) + ") -> ::w::HRESULT";
return "fn " + name + "(" + String.Join(", ", GetParameterDeclarations()) + ") -> HRESULT";
}

public IEnumerable<string> GetParameterDeclarations()
Expand Down
20 changes: 10 additions & 10 deletions Generator/Types/TypeHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ private static string GetElementTypeName(Generator gen, ITypeRequestSource sourc
{
switch (usage)
{
case TypeUsage.Raw: return "::w::HSTRING";
case TypeUsage.Raw: return "HSTRING";
case TypeUsage.In: return "&HStringArg";
case TypeUsage.Out: return "HString";
case TypeUsage.GenericArg: return "HString";
Expand All @@ -98,7 +98,7 @@ private static string GetElementTypeName(Generator gen, ITypeRequestSource sourc
}
else if (t.FullName == "System.Guid")
{
return "::Guid";
return "Guid";
}
else if (t.IsPrimitive)
{
Expand Down Expand Up @@ -127,7 +127,7 @@ private static string GetElementTypeName(Generator gen, ITypeRequestSource sourc
case "System.Double":
return "f64";
case "System.Char":
return "::Char";
return "Char";
default:
throw new NotImplementedException("Primitive type: " + t.FullName);
}
Expand Down Expand Up @@ -268,19 +268,19 @@ public static string CreateUninitializedOutput(TypeReference t)
}
else if (t.IsArray)
{
return "::std::ptr::null_mut()"; // TODO?
return "null_mut()"; // TODO?
}
else if (t.FullName == "System.String")
{
return "::std::ptr::null_mut()";
return "null_mut()";
}
else if (t.FullName == "System.Object")
{
return "::std::ptr::null_mut()";
return "null_mut()";
}
else if (t.FullName == "System.Guid")
{
return "::std::mem::zeroed()";
return "zeroed()";
}
else if (t.IsPrimitive)
{
Expand All @@ -297,18 +297,18 @@ public static string CreateUninitializedOutput(TypeReference t)
case "System.Single":
case "System.Double":
case "System.Char":
return "::std::mem::zeroed()";
return "zeroed()";
default:
throw new NotImplementedException("Primitive type: " + t.FullName);
}
}
else if (t.IsValueType)
{
return "::std::mem::zeroed()";
return "zeroed()";
}
else // reference type
{
return "::std::ptr::null_mut()";
return "null_mut()";
}
}

Expand Down
42 changes: 16 additions & 26 deletions examples/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,14 @@ extern crate runtimeobject;
use std::ptr;

use wrt::*;
use runtimeobject::*;

// TODO: re-export necessary types from winapi
use ::w::{
HRESULT,
S_OK,
RO_INIT_MULTITHREADED,
};

use wrt::windows::foundation::*;
use wrt::windows::devices::enumeration::*;
use wrt::windows::devices::midi::*;

fn main() {
unsafe {
let hres = RoInitialize(RO_INIT_MULTITHREADED);
println!("HRESULT (RoInitialize) = {}", hres);
let mut f: ::w::UINT32 = 0;
assert!(RoGetErrorReportingFlags(&mut f) == S_OK);
println!("ErrorReportingFlags: {:?}", f);
run();
RoUninitialize();
}
let rt = RuntimeContext::init();
run();
rt.uninit();
}

fn run() {
Expand Down Expand Up @@ -58,27 +43,30 @@ fn run() {
let mut deviceInformationStatics = IDeviceInformationStatics::factory();

unsafe {
use runtimeobject::*;
use ::w::S_OK;

// Test some error reporting by using an invalid device selector
let wrongDeviceSelector: FastHString = "Foobar".into();
let res = deviceInformationStatics.find_all_async_aqs_filter(&wrongDeviceSelector);
if let Err(hr) = res {
println!("HRESULT (FindAllAsyncAqsFilter) = {:?}", hr);
if let Err(e) = res {
println!("HRESULT (FindAllAsyncAqsFilter) = {:?}", e.as_hresult());
let mut errorInfo = {
let mut res = ptr::null_mut();
assert_eq!(GetRestrictedErrorInfo(&mut res), S_OK);
ComPtr::wrap(res)
};
let (description, error, restrictedDescription, _) = {
let mut description = ptr::null_mut();
let mut error: HRESULT = 0;
let mut error = 0;
let mut restrictedDescription = ptr::null_mut();
let mut capabilitySid = ptr::null_mut();
assert_eq!(errorInfo.GetErrorDetails(&mut description, &mut error, &mut restrictedDescription, &mut capabilitySid), S_OK);
(BStr::wrap(description), error, BStr::wrap(restrictedDescription), BStr::wrap(capabilitySid))
};
println!("Got Error Info: {} ({})", description, restrictedDescription);
assert_eq!(error, hr); // the returned HRESULT within IRestrictedErrorInfo is the same as the original HRESULT
}
assert_eq!(error, e.as_hresult()); // the returned HRESULT within IRestrictedErrorInfo is the same as the original HRESULT
}
// NOTE: `res` is still null pointer at this point
};

Expand Down Expand Up @@ -111,7 +99,7 @@ fn run() {
let mut started = lock.lock().unwrap();
*started = true;
cvar.notify_one();
S_OK
Ok(())
});
unsafe { asyncOp.set_completed(&mut myHandler).unwrap() };
// local reference to myHandler is dropped here -> Release() is called
Expand Down Expand Up @@ -145,7 +133,6 @@ fn run() {
assert_eq!(i, count);

let mut buffer = Vec::with_capacity(2000);

unsafe { deviceInformationCollection.get_many(0, &mut buffer).unwrap() };
for (b, i) in buffer.iter_mut().zip(0..) {
let deviceName = unsafe { b.get_name().unwrap() };
Expand All @@ -160,7 +147,10 @@ fn run() {
println!("Found remembered value: {} (index: {})", found, index);
}

assert!(unsafe { deviceInformationCollection.get_at(count + 42).is_err() }); // will be E_BOUNDS (out of bounds)
match unsafe { deviceInformationCollection.get_at(count + 42) } {
Err(e) => println!("Error getting element at {}: {:?}", count + 42, e), // will be out of bounds
Ok(_) => panic!("expected Error")
};

let array = &mut [true, false, false, true];
let boxed_array = unsafe { IPropertyValueStatics::factory().create_boolean_array(array) };
Expand Down
7 changes: 3 additions & 4 deletions src/cominterfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ pub trait ComIid {
// extend some definitions from winapi (re-export existing types where possible!)
DEFINE_IID!(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
pub type IUnknown = ::w::IUnknown;
pub type IUnknownVtbl = ::w::IUnknownVtbl;
impl ComIid for IUnknown { fn iid() -> &'static Guid { &IID_IUnknown } }
impl ComInterface for IUnknown { type Vtbl = IUnknownVtbl; }
impl ComInterface for IUnknown { type Vtbl = ::w::IUnknownVtbl; }

DEFINE_IID!(IID_IRestrictedErrorInfo, 0x82BA7092, 0x4C88, 0x427D, 0xA7, 0xBC, 0x16, 0xDD, 0x93, 0xFE, 0xB6, 0x7E);
pub type IRestrictedErrorInfo = ::w::IRestrictedErrorInfo;
Expand All @@ -33,7 +32,7 @@ DEFINE_IID!(IID_IAgileObject, 0x94EA2B94, 0xE9CC, 0x49E0, 0xC0, 0xFF, 0xEE, 0x64

#[repr(C)] #[derive(Debug)]
pub struct IAgileObject {
lpVtbl: *const IUnknownVtbl // IAgileObject has no methods besides what IUnknown has
lpVtbl: *const ::w::IUnknownVtbl // IAgileObject has no methods besides what IUnknown has
}
impl ::std::ops::Deref for IAgileObject {
type Target = IUnknown;
Expand All @@ -49,4 +48,4 @@ impl ::std::ops::DerefMut for IAgileObject {
}
}
impl ComIid for IAgileObject { fn iid() -> &'static Guid { &IID_IAgileObject } }
impl ComInterface for IAgileObject { type Vtbl = IUnknownVtbl; }
impl ComInterface for IAgileObject { type Vtbl = ::w::IUnknownVtbl; }
5 changes: 3 additions & 2 deletions src/comptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt;
use std::ptr;
use ::{ComIid, ComInterface, RtInterface, RtClassInterface, IInspectable, Guid};

#[derive(Debug)]
#[repr(C)] #[derive(Debug)]
pub struct ComPtr<T>(*mut T); // TODO: use NonZero or Shared (see https://github.com/rust-lang/rust/issues/27730)

impl<T> fmt::Pointer for ComPtr<T> {
Expand Down Expand Up @@ -84,7 +84,8 @@ impl<T> PartialEq<ComPtr<T>> for ComPtr<T> {
}
}

/// Owned array type that will be deallocated using `CoTaskMemFree` on drop.
/// Owned array type that is returned from WinRT calls.
/// Has been allocated by WinRT and will be deallocated using `CoTaskMemFree` on drop.
pub struct ComArray<T> where T: ::RtType {
size: u32,
first: *mut T::Abi
Expand Down
24 changes: 19 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,35 @@ mod comptr;
pub use comptr::{ComPtr, ComArray};

mod cominterfaces;
pub use cominterfaces::{ComInterface, ComIid, IUnknown, IUnknownVtbl, IRestrictedErrorInfo, IAgileObject};
// TODO: get rid of IUnknownVtbl export?
pub use cominterfaces::{ComInterface, ComIid, IUnknown, IRestrictedErrorInfo, IAgileObject};

mod rt;
pub use rt::{RtInterface, RtClassInterface, RtValueType, RtType, RtActivatable, IInspectable, IInspectableVtbl, RtResult, Char};
pub use rt::{RtInterface, RtClassInterface, RtValueType, RtType, RtActivatable, IInspectable, IInspectableVtbl, Char, RuntimeContext};

pub use rt::handler::IntoInterface;

mod result;
pub use result::{Result, Error, HRESULT};

pub mod windows {
pub use rt::gen::windows::*;
}

/// This is only for internal use within the generated code
mod prelude {
pub use ::rt::{RtType, IInspectable, RtResult};
pub use ::rt::{RtType, IInspectable, IInspectableVtbl, Char};
pub use ::rt::handler::IntoInterface;
pub use ::{ComInterface, HString, HStringArg, ComPtr, ComArray, ComIid, IUnknown};
pub use ::cominterfaces::{ComInterface, ComIid, IUnknown};
pub use ::comptr::{ComPtr, ComArray};
pub use ::hstring::{HString, HStringArg};
pub use ::result::{Result, HRESULT};
pub use ::w::{IUnknownVtbl, S_OK, HSTRING};
pub use ::std::ptr::null_mut;
pub use ::std::mem::zeroed;
pub use ::guid::Guid;

#[inline]
pub fn err<T>(hr: ::result::HRESULT) -> ::result::Result<T> {
Err(::result::Error::from_hresult(hr))
}
}
64 changes: 64 additions & 0 deletions src/result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
pub type HRESULT = ::w::HRESULT; // re-export HRESULT from WinAPI

// TODO: add more codes from https://msdn.microsoft.com/en-us/library/windows/desktop/dd542643(v=vs.85).aspx, especially the `RO_`-prefixed

#[derive(Debug, PartialEq, Eq)]
pub enum Error {
OperationAborted,
AccessDenied, // UnauthorizedAccessException in .NET (https://msdn.microsoft.com/en-us/library/awy7adbx(v=vs.110).aspx)
UnspecifiedFailure,
InvalidHandle,
InvalidArgument,
NoSuchInterface,
NotImplemented, // NotImplementedException in .NET (https://msdn.microsoft.com/en-us/library/9ztbc5s1(v=vs.110).aspx)
OutOfMemory, // OutOfMemoryException in .NET (https://msdn.microsoft.com/en-us/library/9ztbc5s1(v=vs.110).aspx)
InvalidPointer,
UnexpectedFailure,
OutOfBounds,
IllegalMethodCall,
Other(HRESULT)
}

impl Error {
pub fn from_hresult(hr: HRESULT) -> Error {
use Error::*;

match hr {
::w::E_ABORT => OperationAborted,
::w::E_ACCESSDENIED => AccessDenied,
::w::E_FAIL => UnspecifiedFailure,
::w::E_HANDLE => InvalidHandle,
::w::E_INVALIDARG => InvalidArgument,
::w::E_NOINTERFACE => NoSuchInterface,
::w::E_NOTIMPL => NotImplemented,
::w::E_OUTOFMEMORY => OutOfMemory,
::w::E_POINTER => InvalidPointer,
::w::E_UNEXPECTED => UnexpectedFailure,
::w::E_BOUNDS => OutOfBounds,
::w::E_ILLEGAL_METHOD_CALL => IllegalMethodCall,
_ => Other(hr)
}
}

pub fn as_hresult(&self) -> HRESULT {
use Error::*;

match *self {
OperationAborted => ::w::E_ABORT,
AccessDenied => ::w::E_ACCESSDENIED,
UnspecifiedFailure => ::w::E_FAIL,
InvalidHandle => ::w::E_HANDLE,
InvalidArgument => ::w::E_INVALIDARG,
NoSuchInterface => ::w::E_NOINTERFACE,
NotImplemented => ::w::E_NOTIMPL,
OutOfMemory => ::w::E_OUTOFMEMORY,
InvalidPointer => ::w::E_POINTER,
UnexpectedFailure => ::w::E_UNEXPECTED,
OutOfBounds => ::w::E_BOUNDS,
IllegalMethodCall => ::w::E_ILLEGAL_METHOD_CALL,
Other(hr) => hr,
}
}
}

pub type Result<T> = ::std::result::Result<T, Error>;
Loading

0 comments on commit a7ee7de

Please sign in to comment.