diff --git a/Docs/How it works.md b/Docs/How it works.md index a950c753..c6f6e91f 100644 --- a/Docs/How it works.md +++ b/Docs/How it works.md @@ -90,7 +90,7 @@ extension COMInterop when T == SWRT_IFoo { func getName() throws -> String { var name: BSTR? = nil defer { BStrProjection.release(&name) } - try HResult.throwIfFailed(pointer.pointee.vtable.pointee.GetName(pointer, &name)) + try COMError.fromABI(pointer.pointee.vtable.pointee.GetName(pointer, &name)) return BStrProjection.toSwift(name) } } diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IIterable_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IIterable_swift index 3513b79a..18ac79ad 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IIterable_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IIterable_swift @@ -37,7 +37,7 @@ internal class SequenceIterator: WinRTPrimaryExport Bool { current != nil } func _current() throws -> T { - guard let current else { throw HResult.Error.illegalMethodCall } + guard let current else { throw COMError.illegalMethodCall } return current } @@ -47,6 +47,6 @@ internal class SequenceIterator: WinRTPrimaryExport UInt32 { - throw HResult.Error.notImpl // TODO(#31): Implement out arrays + throw COMError.notImpl // TODO(#31): Implement out arrays } } \ No newline at end of file diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVectorView_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVectorView_swift index 479a6c9c..75feecb3 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVectorView_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVectorView_swift @@ -48,6 +48,6 @@ fileprivate class CollectionVectorView: WinRTPrimaryExport UInt32 { - throw HResult.Error.notImpl // TODO(#31): Implement out arrays + throw COMError.notImpl // TODO(#31): Implement out arrays } } \ No newline at end of file diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVector_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVector_swift index 58133481..0df03d5c 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVector_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVector_swift @@ -74,7 +74,7 @@ public class ArrayVector: WinRTPrimaryExport, } public func getMany(_ startIndex: UInt32, _ items: [T]) throws -> UInt32 { - throw HResult.Error.notImpl // TODO(#31): Implement out arrays + throw COMError.notImpl // TODO(#31): Implement out arrays } public func replaceAll(_ items: [T]) throws { diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncActionWithProgress_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncActionWithProgress_swift index 6140e16f..4f0b5bb8 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncActionWithProgress_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncActionWithProgress_swift @@ -5,7 +5,7 @@ extension WindowsFoundation_IAsyncActionWithProgressProtocol { public func get() async throws { if try _status() == .started { // We can't await if the completed handler is already set - guard try COM.NullResult.catch(_completed()) == nil else { throw COM.HResult.Error.illegalMethodCall } + guard try COM.NullResult.catch(_completed()) == nil else { throw COM.COMError.illegalMethodCall } let awaiter = WindowsRuntime.AsyncAwaiter() try _completed({ _, _ in _Concurrency.Task { await awaiter.signal() } }) await awaiter.wait() diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncAction_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncAction_swift index 09534329..702f8271 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncAction_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncAction_swift @@ -5,7 +5,7 @@ extension WindowsFoundation_IAsyncActionProtocol { public func get() async throws { if try _status() == .started { // We can't await if the completed handler is already set - guard try COM.NullResult.catch(_completed()) == nil else { throw COM.HResult.Error.illegalMethodCall } + guard try COM.NullResult.catch(_completed()) == nil else { throw COM.COMError.illegalMethodCall } let awaiter = WindowsRuntime.AsyncAwaiter() try _completed({ _, _ in _Concurrency.Task { await awaiter.signal() } }) await awaiter.wait() diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperationWithProgress_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperationWithProgress_swift index 7528d6d9..413cdf79 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperationWithProgress_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperationWithProgress_swift @@ -5,7 +5,7 @@ extension WindowsFoundation_IAsyncOperationWithProgressProtocol { public func get() async throws -> TResult { if try _status() == .started { // We can't await if the completed handler is already set - guard try COM.NullResult.catch(_completed()) == nil else { throw COM.HResult.Error.illegalMethodCall } + guard try COM.NullResult.catch(_completed()) == nil else { throw COM.COMError.illegalMethodCall } let awaiter = WindowsRuntime.AsyncAwaiter() try _completed({ _, _ in _Concurrency.Task { await awaiter.signal() } }) await awaiter.wait() diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperation_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperation_swift index 799fc331..ada68cdd 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperation_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperation_swift @@ -5,7 +5,7 @@ extension WindowsFoundation_IAsyncOperationProtocol { public func get() async throws -> TResult { if try _status() == .started { // We can't await if the completed handler is already set - guard try COM.NullResult.catch(_completed()) == nil else { throw COM.HResult.Error.illegalMethodCall } + guard try COM.NullResult.catch(_completed()) == nil else { throw COM.COMError.illegalMethodCall } let awaiter = WindowsRuntime.AsyncAwaiter() try _completed({ _, _ in _Concurrency.Task { await awaiter.signal() } }) await awaiter.wait() diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IMemoryBuffer_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IMemoryBuffer_swift index 9a1c7084..175e37d7 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IMemoryBuffer_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IMemoryBuffer_swift @@ -3,7 +3,7 @@ import WindowsRuntime extension Array where Element == UInt8 { public init(_ buffer: WindowsFoundation_IMemoryBuffer) throws { let reference = try buffer.createReference() - guard let bufferPointer = try reference.bytes else { throw HResult.Error.fail } + guard let bufferPointer = try reference.bytes else { throw COMError.fail } self.init(bufferPointer) } } \ No newline at end of file diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_MemoryBuffer_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_MemoryBuffer_swift index 76c6e6de..0c472dd4 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_MemoryBuffer_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_MemoryBuffer_swift @@ -4,7 +4,7 @@ extension WindowsFoundation_MemoryBuffer { public convenience init(_ bytes: [UInt8]) throws { try self.init(UInt32(bytes.count)) let reference = try self.createReference() - guard let bufferPointer = try reference.bytes else { throw HResult.Error.fail } + guard let bufferPointer = try reference.bytes else { throw COMError.fail } _ = bufferPointer.update(fromContentsOf: bytes) } } \ No newline at end of file diff --git a/Generator/Sources/SwiftWinRT/Writing/COMInteropExtension.swift b/Generator/Sources/SwiftWinRT/Writing/COMInteropExtension.swift index 127ad247..0bc24d74 100644 --- a/Generator/Sources/SwiftWinRT/Writing/COMInteropExtension.swift +++ b/Generator/Sources/SwiftWinRT/Writing/COMInteropExtension.swift @@ -151,7 +151,7 @@ fileprivate func writeSwiftToABICall( } func writeCall() throws { - writer.writeStatement("try WinRTError.throwIfFailed(" + writer.writeStatement("try WinRTError.fromABI(" + "this.pointee.VirtualTable.pointee.\(abiMethodName)(" + "\(abiArgs.joined(separator: ", "))))") } @@ -181,7 +181,7 @@ fileprivate func writeSwiftToABICall( let returnValue: String switch returnTypeProjection.kind { case .identity where returnCOMReference: - writer.writeStatement("guard let \(returnParam.name) else { throw HResult.Error.pointer }") + writer.writeStatement("guard let \(returnParam.name) else { throw COMError.pointer }") returnValue = "\(SupportModules.COM.comReference)(transferringRef: \(returnParam.name))" case .identity where !returnCOMReference: returnValue = returnParam.name diff --git a/Generator/Sources/SwiftWinRT/Writing/VirtualTable.swift b/Generator/Sources/SwiftWinRT/Writing/VirtualTable.swift index 385f993b..0a0f7164 100644 --- a/Generator/Sources/SwiftWinRT/Writing/VirtualTable.swift +++ b/Generator/Sources/SwiftWinRT/Writing/VirtualTable.swift @@ -78,10 +78,10 @@ fileprivate func writeVirtualTableFunc( // Ensure non-optional by reference params are non-null pointers for param in params { guard case .reference(in: _, out: _, optional: false) = param.passBy else { continue } - output.writeFullLine("guard let \(param.name) else { throw COM.HResult.Error.pointer }") + output.writeFullLine("guard let \(param.name) else { throw COM.COMError.pointer }") } if let returnParam { - output.writeFullLine("guard let \(returnParam.name) else { throw COM.HResult.Error.pointer }") + output.writeFullLine("guard let \(returnParam.name) else { throw COM.COMError.pointer }") } // Declare the Swift representation of params diff --git a/InteropTests/Tests/AsyncTests.swift b/InteropTests/Tests/AsyncTests.swift index 1cd31dd0..45c81444 100644 --- a/InteropTests/Tests/AsyncTests.swift +++ b/InteropTests/Tests/AsyncTests.swift @@ -21,7 +21,7 @@ class AsyncTests : XCTestCase { let _ = try await asyncOperation.get() XCTFail("Expected an exception to be thrown") } - catch let error as COMError { + catch let error as COMErrorProtocol { XCTAssertEqual(error.hresult, HResult.outOfMemory) } } @@ -43,7 +43,7 @@ class AsyncTests : XCTestCase { let _ = try await asyncOperation.get() XCTFail("Expected an exception to be thrown") } - catch let error as COMError { + catch let error as COMErrorProtocol { XCTAssertEqual(try asyncOperation._status(), .error) XCTAssertEqual(error.hresult, HResult.outOfMemory) } @@ -56,7 +56,7 @@ class AsyncTests : XCTestCase { let _ = try await asyncOperation.get() XCTFail("Expected an exception to be thrown") } - catch let error as COMError { + catch let error as COMErrorProtocol { XCTAssertEqual(try asyncOperation._status(), .started) XCTAssertEqual(error.hresult, HResult.illegalMethodCall) } diff --git a/InteropTests/Tests/ErrorTests.swift b/InteropTests/Tests/ErrorTests.swift index ac80f71c..0dea0b20 100644 --- a/InteropTests/Tests/ErrorTests.swift +++ b/InteropTests/Tests/ErrorTests.swift @@ -9,7 +9,7 @@ class ErrorTests: WinRTTestCase { do { try Errors.failWith(hresult, "") XCTFail("Expected an error") - } catch let error as COMError { + } catch let error as COMErrorProtocol { XCTAssertEqual(error.hresult, hresult) } } @@ -31,14 +31,29 @@ class ErrorTests: WinRTTestCase { } func testThrowWithHResult() throws { - let hresult = HResult(unsigned: 0xCAFEBABE) - let error = try XCTUnwrap(HResult.Error(hresult: hresult)) - XCTAssertEqual( - try Errors.catchHResult { throw error }, - hresult) + struct TestError: ErrorWithHResult { + public var hresult: HResult { .init(unsigned: 0xCAFEBABE) } + } + let error = TestError() + XCTAssertEqual(try Errors.catchHResult { throw error }, error.hresult) } func testThrowWithMessage() throws { - throw XCTSkip("Not implemented: RoOriginateError") + struct TestError: Error, CustomStringConvertible { + public var description: String { "test" } + } + let error = TestError() + XCTAssertEqual(try Errors.catchMessage { throw error }, error.description) + } + + func testSwiftErrorPreserved() throws { + try XCTSkipIf(true, "TODO(#248): Fix preserving Swift error objects across the WinRT boundary.") + + struct SwiftError: Error {} + do { + try Errors.call { throw SwiftError() } + XCTFail("Expected an error") + } + catch _ as SwiftError {} // Success } } \ No newline at end of file diff --git a/InteropTests/WinRTComponent/Errors.cpp b/InteropTests/WinRTComponent/Errors.cpp index 73b27f35..7da694b2 100644 --- a/InteropTests/WinRTComponent/Errors.cpp +++ b/InteropTests/WinRTComponent/Errors.cpp @@ -16,6 +16,10 @@ namespace winrt::WinRTComponent::implementation { throw winrt::hresult_not_implemented(); } + void Errors::Call(winrt::WinRTComponent::MinimalDelegate const& callee) + { + callee(); + } winrt::hresult Errors::CatchHResult(winrt::WinRTComponent::MinimalDelegate const& callee) { try { callee(); } diff --git a/InteropTests/WinRTComponent/Errors.h b/InteropTests/WinRTComponent/Errors.h index 0218f5e8..15e65a24 100644 --- a/InteropTests/WinRTComponent/Errors.h +++ b/InteropTests/WinRTComponent/Errors.h @@ -10,6 +10,7 @@ namespace winrt::WinRTComponent::implementation static void FailWith(winrt::hresult const& hr, winrt::hstring const& message); static hstring NotImplementedProperty(); static void NotImplementedProperty(hstring const& value); + static void Call(winrt::WinRTComponent::MinimalDelegate const& callee); static winrt::hresult CatchHResult(winrt::WinRTComponent::MinimalDelegate const& callee); static winrt::hstring CatchMessage(winrt::WinRTComponent::MinimalDelegate const& callee); }; diff --git a/InteropTests/WinRTComponent/Errors.idl b/InteropTests/WinRTComponent/Errors.idl index 119d5809..6193a413 100644 --- a/InteropTests/WinRTComponent/Errors.idl +++ b/InteropTests/WinRTComponent/Errors.idl @@ -6,6 +6,7 @@ namespace WinRTComponent { static void FailWith(Windows.Foundation.HResult hr, String message); static String NotImplementedProperty; + static void Call(MinimalDelegate callee); static Windows.Foundation.HResult CatchHResult(MinimalDelegate callee); static String CatchMessage(MinimalDelegate callee); }; diff --git a/Support/Sources/COM/COMEmbedding.swift b/Support/Sources/COM/COMEmbedding.swift index 795def27..7036a29f 100644 --- a/Support/Sources/COM/COMEmbedding.swift +++ b/Support/Sources/COM/COMEmbedding.swift @@ -122,10 +122,12 @@ public enum IUnknownVirtualTable { _ this: UnsafeMutablePointer?, _ iid: UnsafePointer?, _ ppvObject: UnsafeMutablePointer?) -> COM_ABI.SWRT_HResult { - guard let this, let iid, let ppvObject else { return HResult.invalidArg.value } + guard let this, let iid, let ppvObject else { return COMError.toABI(hresult: HResult.invalidArg) } ppvObject.pointee = nil - return HResult.catchValue { + // Avoid setting the error info upon failure since QueryInterface is called + // by RoOriginateError, which is trying to set the error info itself. + return COMError.toABI(setErrorInfo: false) { let id = GUIDProjection.toSwift(iid.pointee) let this = IUnknownPointer(OpaquePointer(this)) let reference = id == uuidof(SWRT_SwiftCOMObject.self) diff --git a/Support/Sources/COM/COMError.swift b/Support/Sources/COM/COMError.swift index 9489eb65..3075f7fe 100644 --- a/Support/Sources/COM/COMError.swift +++ b/Support/Sources/COM/COMError.swift @@ -1,4 +1,115 @@ -/// Protocol for errors which result from a COM error HRESULT. -public protocol COMError: Error { +import COM_ABI + +/// Protocol for errors with an associated HResult value. +public protocol ErrorWithHResult: Error { var hresult: HResult { get } +} + +public protocol COMErrorProtocol: ErrorWithHResult { + /// Gets the error info for + var errorInfo: IErrorInfo? { get } + + /// Converts this COM error to its ABI representation, including thread-local COM error information. + func toABI(setErrorInfo: Bool) -> HResult.Value +} + +extension COMErrorProtocol { + /// Converts this COM error to its ABI representation, including thread-local COM error information. + public func toABI() -> HResult.Value { toABI(setErrorInfo: true) } +} + +/// Captures a failure from a COM API invocation (HRESULT + optional IErrorInfo). +public struct COMError: COMErrorProtocol, CustomStringConvertible { + public static let fail = Self(hresult: HResult.fail) + public static let illegalMethodCall = Self(hresult: HResult.illegalMethodCall) + public static let invalidArg = Self(hresult: HResult.invalidArg) + public static let notImpl = Self(hresult: HResult.notImpl) + public static let noInterface = Self(hresult: HResult.noInterface) + public static let pointer = Self(hresult: HResult.pointer) + public static let outOfMemory = Self(hresult: HResult.outOfMemory) + + public let hresult: HResult // Invariant: isFailure + public let errorInfo: IErrorInfo? + + public init(hresult: HResult, errorInfo: IErrorInfo? = nil) { + assert(hresult.isFailure) + self.hresult = hresult + self.errorInfo = errorInfo + } + + public init(hresult: HResult, description: String?) { + self.init(hresult: hresult, errorInfo: description.map { DescriptiveErrorInfo(description: $0) }) + } + + public var description: String { + if let errorInfo, let description = try? errorInfo.description { return description } + return hresult.description + } + + public func toABI(setErrorInfo: Bool = true) -> HResult.Value { + if setErrorInfo { try? Self.setErrorInfo(errorInfo) } + return hresult.value + } + + /// Throws any failure HRESULTs as COMErrors, optionally capturing the COM thread error info. + @discardableResult + public static func fromABI(captureErrorInfo: Bool = true, _ hresult: HResult.Value) throws -> HResult { + let hresult = HResult(hresult) + guard hresult.isFailure else { return hresult } + guard captureErrorInfo else { throw COMError(hresult: hresult) } + + let errorInfo = try? Self.getErrorInfo() + if let swiftErrorInfo = errorInfo as? SwiftErrorInfo, swiftErrorInfo.hresult == hresult { + // This was originally a Swift error, throw it as such. + throw swiftErrorInfo.error + } + + throw COMError(hresult: hresult, errorInfo: errorInfo) + } + + /// Catches any thrown errors from a provided closure, converting it to an HRESULT and optionally setting the COM thread error info state. + public static func toABI(setErrorInfo: Bool = true, _ body: () throws -> Void) -> HResult.Value { + do { try body() } + catch { return toABI(error: error, setErrorInfo: setErrorInfo) } + return HResult.ok.value + } + + public static func toABI(error: Error, setErrorInfo: Bool = true) -> HResult.Value { + // If the error already came from COM/WinRT, propagate it + if let comError = error as? any COMErrorProtocol { return comError.toABI(setErrorInfo: setErrorInfo) } + + // Otherwise, create a new error info and set it + return SwiftErrorInfo(error: error).toABI(setErrorInfo: setErrorInfo) + } + + public static func toABI(hresult: HResult, description: String? = nil) -> HResult.Value { + guard hresult.isFailure else { return hresult.value } + try? Self.setErrorInfo(description.map { DescriptiveErrorInfo(description: $0) }) + return hresult.value + } + + public static func getErrorInfo() throws -> IErrorInfo? { + var errorInfo: UnsafeMutablePointer? + defer { IErrorInfoProjection.release(&errorInfo) } + try fromABI(captureErrorInfo: false, COM_ABI.SWRT_GetErrorInfo(/* dwReserved: */ 0, &errorInfo)) + return IErrorInfoProjection.toSwift(consuming: &errorInfo) + } + + public static func setErrorInfo(_ errorInfo: IErrorInfo?) throws { + var errorInfo = try IErrorInfoProjection.toABI(errorInfo) + defer { IErrorInfoProjection.release(&errorInfo) } + try fromABI(captureErrorInfo: false, COM_ABI.SWRT_SetErrorInfo(/* dwReserved: */ 0, errorInfo)) + } + + private final class DescriptiveErrorInfo: COMPrimaryExport, IErrorInfoProtocol { + private let _description: String + public init(description: String) { self._description = description } + + // IErrorInfo + public var guid: GUID { get throws { throw COMError.fail } } + public var source: String? { get throws { throw COMError.fail } } + public var description: String? { self._description } + public var helpFile: String? { get throws { throw COMError.fail } } + public var helpContext: UInt32 { get throws { throw COMError.fail } } + } } \ No newline at end of file diff --git a/Support/Sources/COM/COMInterop.swift b/Support/Sources/COM/COMInterop.swift index 911b32a0..da7e4925 100644 --- a/Support/Sources/COM/COMInterop.swift +++ b/Support/Sources/COM/COMInterop.swift @@ -34,10 +34,11 @@ public struct COMInterop { public func queryInterface(_ id: COMInterfaceID) throws -> IUnknownReference { var iid = GUIDProjection.toABI(id) var rawPointer: UnsafeMutableRawPointer? = nil - try HResult.throwIfFailed(unknown.pointee.VirtualTable.pointee.QueryInterface(unknown, &iid, &rawPointer)) + // Avoid calling GetErrorInfo since RoOriginateError causes QueryInterface calls + try COMError.fromABI(captureErrorInfo: false, unknown.pointee.VirtualTable.pointee.QueryInterface(unknown, &iid, &rawPointer)) guard let rawPointer else { assertionFailure("QueryInterface succeeded but returned a null pointer") - throw HResult.Error.noInterface + throw COMError.noInterface } let pointer = rawPointer.bindMemory(to: COM_ABI.SWRT_IUnknown.self, capacity: 1) diff --git a/Support/Sources/COM/COMPrimaryExport.swift b/Support/Sources/COM/COMPrimaryExport.swift index 38ff61cf..9c522289 100644 --- a/Support/Sources/COM/COMPrimaryExport.swift +++ b/Support/Sources/COM/COMPrimaryExport.swift @@ -24,7 +24,7 @@ open class COMPrimaryExport: COMExportBase Void) -> COM_ABI.SWRT_HResult { - guard let this else { - assertionFailure("COM this pointer was null") - return HResult.pointer.value - } - + public static func _implement(_ this: UnsafeMutablePointer?, _ body: (SwiftObject) throws -> Void) -> COM_ABI.SWRT_HResult { + guard let this else { return COMError.toABI(hresult: HResult.pointer, description: "COM 'this' pointer was null") } let implementation: SwiftObject = COMEmbedding.getImplementationOrCrash(this) - return HResult.catchValue { try body(implementation) } + return COMError.toABI { try body(implementation) } } public static func _set( _ pointer: UnsafeMutablePointer?, _ value: @autoclosure () throws -> Value) throws { - guard let pointer else { throw HResult.Error.pointer } + guard let pointer else { throw COMError.pointer } pointer.pointee = try value() } } diff --git a/Support/Sources/COM/FreeThreadedMarshal.swift b/Support/Sources/COM/FreeThreadedMarshal.swift index 46aac732..8003bb24 100644 --- a/Support/Sources/COM/FreeThreadedMarshal.swift +++ b/Support/Sources/COM/FreeThreadedMarshal.swift @@ -6,34 +6,34 @@ internal class FreeThreadedMarshal: COMSecondaryExport?, _ pv: UnsafeMutableRawPointer?, _ dwDestContext: UInt32, _ pvDestContext: UnsafeMutableRawPointer?, _ mshlflags: UInt32, _ pCid: UnsafeMutablePointer?) throws { - try HResult.throwIfFailed(marshaler.pointer.pointee.VirtualTable.pointee.GetUnmarshalClass( + try COMError.fromABI(marshaler.pointer.pointee.VirtualTable.pointee.GetUnmarshalClass( marshaler.pointer, riid, pv, dwDestContext, pvDestContext, mshlflags, pCid)) } func getMarshalSizeMax(_ riid: UnsafeMutablePointer?, _ pv: UnsafeMutableRawPointer?, _ dwDestContext: UInt32, _ pvDestContext: UnsafeMutableRawPointer?, _ mshlflags: UInt32, _ pSize: UnsafeMutablePointer?) throws { - try HResult.throwIfFailed(marshaler.pointer.pointee.VirtualTable.pointee.GetMarshalSizeMax( + try COMError.fromABI(marshaler.pointer.pointee.VirtualTable.pointee.GetMarshalSizeMax( marshaler.pointer, riid, pv, dwDestContext, pvDestContext, mshlflags, pSize)) } func marshalInterface(_ pStm: OpaquePointer?, _ riid: UnsafeMutablePointer?, _ pv: UnsafeMutableRawPointer?, _ dwDestContext: UInt32, _ pvDestContext: UnsafeMutableRawPointer?, _ mshlflags: UInt32) throws { - try HResult.throwIfFailed(marshaler.pointer.pointee.VirtualTable.pointee.MarshalInterface( + try COMError.fromABI(marshaler.pointer.pointee.VirtualTable.pointee.MarshalInterface( marshaler.pointer, pStm, riid, pv, dwDestContext, pvDestContext, mshlflags)) } func unmarshalInterface(_ pStm: OpaquePointer?, _ riid: UnsafeMutablePointer?, _ pv: UnsafeMutablePointer?) throws { - try HResult.throwIfFailed(marshaler.pointer.pointee.VirtualTable.pointee.UnmarshalInterface( + try COMError.fromABI(marshaler.pointer.pointee.VirtualTable.pointee.UnmarshalInterface( marshaler.pointer, pStm, riid, pv)) } func releaseMarshalData(_ pStm: OpaquePointer?) throws { - try HResult.throwIfFailed(marshaler.pointer.pointee.VirtualTable.pointee.ReleaseMarshalData( + try COMError.fromABI(marshaler.pointer.pointee.VirtualTable.pointee.ReleaseMarshalData( marshaler.pointer, pStm)) } func disconnectObject(_ dwReserved: UInt32) throws { - try HResult.throwIfFailed(marshaler.pointer.pointee.VirtualTable.pointee.DisconnectObject( + try COMError.fromABI(marshaler.pointer.pointee.VirtualTable.pointee.DisconnectObject( marshaler.pointer, dwReserved)) } } diff --git a/Support/Sources/COM/HResult+Error.swift b/Support/Sources/COM/HResult+Error.swift deleted file mode 100644 index e30a00ad..00000000 --- a/Support/Sources/COM/HResult+Error.swift +++ /dev/null @@ -1,54 +0,0 @@ -extension HResult { - public func throwIfFailed() throws { - if let error = Error(hresult: self) { throw error } - } - - @discardableResult - public static func throwIfFailed(_ hr: Value) throws -> Value { - try HResult(hr).throwIfFailed() - return hr - } - - public static func `catch`(_ block: () throws -> Void) -> HResult { - do { - try block() - return HResult.ok - } catch let error as COMError { - return error.hresult - } catch { - return HResult.fail - } - } - - public static func catchValue(_ block: () throws -> Void) -> Value { - `catch`(block).value - } - - /// A Swift error for a failed HResult value. - public struct Error: COMError, Hashable, CustomStringConvertible { - public static let fail = Self(failed: HResult.fail) - public static let illegalMethodCall = Self(failed: HResult.illegalMethodCall) - public static let invalidArg = Self(failed: HResult.invalidArg) - public static let notImpl = Self(failed: HResult.notImpl) - public static let noInterface = Self(failed: HResult.noInterface) - public static let pointer = Self(failed: HResult.pointer) - public static let outOfMemory = Self(failed: HResult.outOfMemory) - - public let hresult: HResult // Invariant: isFailure - - private init(failed hresult: HResult) { - self.hresult = hresult - } - - public init?(hresult: HResult) { - if hresult.isSuccess { return nil } - self.hresult = hresult - } - - public init?(hresult: Value) { - self.init(hresult: HResult(hresult)) - } - - public var description: String { hresult.description } - } -} \ No newline at end of file diff --git a/Support/Sources/COM/IErrorInfo.swift b/Support/Sources/COM/IErrorInfo.swift index 83f28dbe..34e860b8 100644 --- a/Support/Sources/COM/IErrorInfo.swift +++ b/Support/Sources/COM/IErrorInfo.swift @@ -50,31 +50,31 @@ public func uuidof(_: COM_ABI.SWRT_IErrorInfo.Type) -> COMInterfaceID { extension COMInterop where ABIStruct == COM_ABI.SWRT_IErrorInfo { public func getGuid() throws -> GUID { var value = GUIDProjection.abiDefaultValue - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.GetGUID(this, &value)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.GetGUID(this, &value)) return GUIDProjection.toSwift(value) } public func getSource() throws -> String? { var value = BStrProjection.abiDefaultValue - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.GetSource(this, &value)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.GetSource(this, &value)) return BStrProjection.toSwift(consuming: &value) } public func getDescription() throws -> String? { var value = BStrProjection.abiDefaultValue - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.GetDescription(this, &value)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.GetDescription(this, &value)) return BStrProjection.toSwift(consuming: &value) } public func getHelpFile() throws -> String? { var value = BStrProjection.abiDefaultValue - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.GetHelpFile(this, &value)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.GetHelpFile(this, &value)) return BStrProjection.toSwift(consuming: &value) } public func getHelpContext() throws -> UInt32 { var value = UInt32() - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.GetHelpContext(this, &value)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.GetHelpContext(this, &value)) return value } } diff --git a/Support/Sources/COM/SwiftErrorInfo.swift b/Support/Sources/COM/SwiftErrorInfo.swift new file mode 100644 index 00000000..6d082e4a --- /dev/null +++ b/Support/Sources/COM/SwiftErrorInfo.swift @@ -0,0 +1,23 @@ +// Wraps a Swift Error object into an `IErrorInfo` to preserve it across WinRT boundaries. +open class SwiftErrorInfo: COMPrimaryExport, IErrorInfoProtocol { + public let error: Error + + public init(error: Error) { + self.error = error + } + + open func toABI(setErrorInfo: Bool = true) -> HResult.Value { + if setErrorInfo { try? COMError.setErrorInfo(self) } + return hresult.value + } + + public var hresult: HResult { (self.error as? ErrorWithHResult)?.hresult ?? HResult.fail } + public var message: String { String(describing: error) } + + // IErrorInfo + public var guid: GUID { get throws { throw COMError.fail } } + public var source: String? { get throws { throw COMError.fail } } + public var description: String? { self.message } + public var helpFile: String? { get throws { throw COMError.fail } } + public var helpContext: UInt32 { get throws { throw COMError.fail } } +} \ No newline at end of file diff --git a/Support/Sources/COM_ABI/include/SWRT/windows/oaidl.h b/Support/Sources/COM_ABI/include/SWRT/windows/oaidl.h index f75138ab..1175fb93 100644 --- a/Support/Sources/COM_ABI/include/SWRT/windows/oaidl.h +++ b/Support/Sources/COM_ABI/include/SWRT/windows/oaidl.h @@ -1,6 +1,6 @@ #pragma once -#include "SWRT/windows/oleauto.h" +#include "SWRT/windows/wtypes.h" #include "SWRT/windows/unknwn.h" typedef struct SWRT_IErrorInfo { diff --git a/Support/Sources/COM_ABI/include/SWRT/windows/oleauto.h b/Support/Sources/COM_ABI/include/SWRT/windows/oleauto.h index a47c0b62..f1ac7b30 100644 --- a/Support/Sources/COM_ABI/include/SWRT/windows/oleauto.h +++ b/Support/Sources/COM_ABI/include/SWRT/windows/oleauto.h @@ -1,10 +1,11 @@ #pragma once #include -#include - -typedef char16_t* SWRT_BStr; +#include "SWRT/windows/wtypes.h" +#include "SWRT/windows/oaidl.h" +SWRT_HResult SWRT_GetErrorInfo(uint32_t dwReserved, SWRT_IErrorInfo** pperrinfo); +SWRT_HResult SWRT_SetErrorInfo(uint32_t dwReserved, SWRT_IErrorInfo* perrinfo); SWRT_BStr SWRT_SysAllocString(const char16_t* strIn); SWRT_BStr SWRT_SysAllocStringLen(const char16_t* strIn, uint32_t ui); void SWRT_SysFreeString(SWRT_BStr bstrString); diff --git a/Support/Sources/COM_ABI/include/SWRT/windows/wtypes.h b/Support/Sources/COM_ABI/include/SWRT/windows/wtypes.h new file mode 100644 index 00000000..2ba6b9cf --- /dev/null +++ b/Support/Sources/COM_ABI/include/SWRT/windows/wtypes.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +typedef char16_t* SWRT_BStr; \ No newline at end of file diff --git a/Support/Sources/COM_ABI/include/module.modulemap b/Support/Sources/COM_ABI/include/module.modulemap index 38319687..30c41889 100644 --- a/Support/Sources/COM_ABI/include/module.modulemap +++ b/Support/Sources/COM_ABI/include/module.modulemap @@ -7,5 +7,6 @@ module COM_ABI { header "SWRT/windows/objidl.h" header "SWRT/windows/oleauto.h" header "SWRT/windows/unknwn.h" + header "SWRT/windows/wtypes.h" export * } diff --git a/Support/Sources/COM_ABI/oleauto.c b/Support/Sources/COM_ABI/oleauto.c index 959e5775..0d8559a6 100644 --- a/Support/Sources/COM_ABI/oleauto.c +++ b/Support/Sources/COM_ABI/oleauto.c @@ -3,6 +3,14 @@ #include #include +SWRT_HResult SWRT_GetErrorInfo(uint32_t dwReserved, SWRT_IErrorInfo** pperrinfo) { + return (SWRT_HResult)GetErrorInfo(dwReserved, (IErrorInfo**)pperrinfo); +} + +SWRT_HResult SWRT_SetErrorInfo(uint32_t dwReserved, SWRT_IErrorInfo* perrinfo) { + return (SWRT_HResult)SetErrorInfo(dwReserved, (IErrorInfo*)perrinfo); +} + SWRT_BStr SWRT_SysAllocString(const char16_t* strIn) { return (SWRT_BStr)SysAllocString((const OLECHAR*)strIn); } diff --git a/Support/Sources/WindowsRuntime/EventInvocationList.swift b/Support/Sources/WindowsRuntime/EventInvocationList.swift index 06c8745b..75a95a1d 100644 --- a/Support/Sources/WindowsRuntime/EventInvocationList.swift +++ b/Support/Sources/WindowsRuntime/EventInvocationList.swift @@ -5,13 +5,13 @@ public struct EventInvocationList: ~Copyable { public init() {} public mutating func add(_ handler: Delegate?) throws -> EventRegistration { - guard let handler else { throw HResult.Error.pointer } + guard let handler else { throw COMError.pointer } if implementation == nil { implementation = Implementation() } return try implementation!.add(handler) } public mutating func remove(_ token: WindowsRuntime.EventRegistrationToken) throws { - guard let implementation else { throw HResult.Error.invalidArg } + guard let implementation else { throw COMError.invalidArg } try implementation.remove(token) } @@ -31,7 +31,7 @@ public struct EventInvocationList: ~Copyable { } public func remove(_ token: WindowsRuntime.EventRegistrationToken) throws { - guard let index = handlers.firstIndex(where: { $0.token == token }) else { throw HResult.Error.invalidArg } + guard let index = handlers.firstIndex(where: { $0.token == token }) else { throw COMError.invalidArg } handlers.remove(at: index) } diff --git a/Support/Sources/WindowsRuntime/Infra/ActivationFactoryResolver.swift b/Support/Sources/WindowsRuntime/Infra/ActivationFactoryResolver.swift index 9b61d5a9..306c3ef5 100644 --- a/Support/Sources/WindowsRuntime/Infra/ActivationFactoryResolver.swift +++ b/Support/Sources/WindowsRuntime/Infra/ActivationFactoryResolver.swift @@ -27,8 +27,8 @@ public struct SystemActivationFactoryResolver: ActivationFactoryResolver { var iid = GUIDProjection.toABI(interfaceID) var rawPointer: UnsafeMutableRawPointer? - try WinRTError.throwIfFailed(WindowsRuntime_ABI.SWRT_RoGetActivationFactory(activatableId, &iid, &rawPointer)) - guard let rawPointer else { throw HResult.Error.noInterface } + try WinRTError.fromABI(WindowsRuntime_ABI.SWRT_RoGetActivationFactory(activatableId, &iid, &rawPointer)) + guard let rawPointer else { throw COMError.noInterface } let pointer = rawPointer.bindMemory(to: ABIStruct.self, capacity: 1) return COM.COMReference(transferringRef: pointer) @@ -70,11 +70,11 @@ public final class DllActivationFactoryResolver: ActivationFactoryResolver { libraryNameToLoad.withCString(encodedAs: UTF16.self) { name in libraryHandle = WinSDK.LoadLibraryW(name) } - guard libraryHandle != nil else { throw HResult.Error.fail } + guard libraryHandle != nil else { throw COMError.fail } } guard let rawFuncPointer = WinSDK.GetProcAddress(libraryHandle, "DllGetActivationFactory") else { - throw HResult.Error.fail + throw COMError.fail } let funcPointer = unsafeBitCast(rawFuncPointer, to: WindowsRuntime_ABI.SWRT_DllGetActivationFactory.self) @@ -88,8 +88,8 @@ public final class DllActivationFactoryResolver: ActivationFactoryResolver { defer { StringProjection.release(&activatableId) } var factoryPointer: UnsafeMutablePointer? - try WinRTError.throwIfFailed(function(activatableId, &factoryPointer)) - guard let factoryPointer else { throw HResult.Error.noInterface } + try WinRTError.fromABI(function(activatableId, &factoryPointer)) + guard let factoryPointer else { throw COMError.noInterface } return COM.COMReference(transferringRef: factoryPointer) } diff --git a/Support/Sources/WindowsRuntime/Infra/ComposableClass.swift b/Support/Sources/WindowsRuntime/Infra/ComposableClass.swift index 858c5df9..e21b70ae 100644 --- a/Support/Sources/WindowsRuntime/Infra/ComposableClass.swift +++ b/Support/Sources/WindowsRuntime/Infra/ComposableClass.swift @@ -43,7 +43,7 @@ open class ComposableClass: IInspectableProtocol { // The composed object is useful only when not providing an outer object. var inner: IInspectablePointer? = nil _ = try _factory(IInspectablePointer(OpaquePointer(outer.unknownPointer)), &inner) - guard let inner else { throw HResult.Error.fail } + guard let inner else { throw COMError.fail } self.innerWithRef = inner } else { diff --git a/Support/Sources/WindowsRuntime/Infra/IInspectableVirtualTable.swift b/Support/Sources/WindowsRuntime/Infra/IInspectableVirtualTable.swift index 29d4eb1b..a0a2593c 100644 --- a/Support/Sources/WindowsRuntime/Infra/IInspectableVirtualTable.swift +++ b/Support/Sources/WindowsRuntime/Infra/IInspectableVirtualTable.swift @@ -6,11 +6,11 @@ public enum IInspectableVirtualTable { _ this: UnsafeMutablePointer?, _ count: UnsafeMutablePointer?, _ iids: UnsafeMutablePointer?>?) -> WindowsRuntime_ABI.SWRT_HResult { - guard let this, let count, let iids else { return HResult.invalidArg.value } + guard let this, let count, let iids else { return WinRTError.toABI(hresult: HResult.invalidArg) } count.pointee = 0 iids.pointee = nil let object = COMEmbedding.getEmbedderObjectOrCrash(this) as! IInspectable - return HResult.catchValue { + return WinRTError.toABI { let idsArray = try object.getIids() let comArray = try ArrayProjection.toABI(idsArray) count.pointee = comArray.count @@ -21,10 +21,10 @@ public enum IInspectableVirtualTable { public static func GetRuntimeClassName( _ this: UnsafeMutablePointer?, _ className: UnsafeMutablePointer?) -> WindowsRuntime_ABI.SWRT_HResult { - guard let this, let className else { return HResult.invalidArg.value } + guard let this, let className else { return WinRTError.toABI(hresult: HResult.invalidArg) } className.pointee = nil let object = COMEmbedding.getEmbedderObjectOrCrash(this) as! IInspectable - return HResult.catchValue { + return WinRTError.toABI { className.pointee = try StringProjection.toABI(object.getRuntimeClassName()) } } @@ -32,9 +32,9 @@ public enum IInspectableVirtualTable { public static func GetTrustLevel( _ this: UnsafeMutablePointer?, _ trustLevel: UnsafeMutablePointer?) -> WindowsRuntime_ABI.SWRT_HResult { - guard let this, let trustLevel else { return HResult.invalidArg.value } + guard let this, let trustLevel else { return WinRTError.toABI(hresult: HResult.invalidArg) } let object = COMEmbedding.getEmbedderObjectOrCrash(this) as! IInspectable - return HResult.catchValue { + return WinRTError.toABI { trustLevel.pointee = try TrustLevel.toABI(object.getTrustLevel()) } } diff --git a/Support/Sources/WindowsRuntime/Infra/ProjectionProtocols+extensions.swift b/Support/Sources/WindowsRuntime/Infra/ProjectionProtocols+extensions.swift index 51267f8d..92529886 100644 --- a/Support/Sources/WindowsRuntime/Infra/ProjectionProtocols+extensions.swift +++ b/Support/Sources/WindowsRuntime/Infra/ProjectionProtocols+extensions.swift @@ -14,22 +14,64 @@ extension IReferenceableProjection { } extension ReferenceTypeProjection { + // Shadow COMTwoWayProjection methods to use WinRTError instead of COMError public static func _implement(_ this: UnsafeMutablePointer?, _ body: (SwiftObject) throws -> Void) -> SWRT_HResult { - guard let this else { - assertionFailure("COM this pointer was null") - return HResult.pointer.value + guard let this else { return WinRTError.toABI(hresult: HResult.pointer, message: "WinRT 'this' pointer was null") } + let implementation: SwiftObject = COMEmbedding.getImplementationOrCrash(this) + return WinRTError.toABI { try body(implementation) } + } + + public static func _getter(_ this: ABIPointer?, _ value: UnsafeMutablePointer?, _ code: (SwiftObject) throws -> Value) -> SWRT_HResult { + _implement(this) { + guard let value else { throw COMError.pointer } + value.pointee = try code($0) } + } +} +extension InterfaceProjection { + // Shadow COMTwoWayProjection methods to use WinRTError instead of COMError + public static func _implement(_ this: UnsafeMutablePointer?, _ body: (SwiftObject) throws -> Void) -> SWRT_HResult { + guard let this else { return WinRTError.toABI(hresult: HResult.pointer, message: "WinRT 'this' pointer was null") } let implementation: SwiftObject = COMEmbedding.getImplementationOrCrash(this) - return WinRTError.catchAndOriginate { try body(implementation) } + return WinRTError.toABI { try body(implementation) } } - public static func _getter( - _ this: ABIPointer?, - _ value: UnsafeMutablePointer?, - _ code: (SwiftObject) throws -> Value) -> SWRT_HResult { + public static func _getter(_ this: ABIPointer?, _ value: UnsafeMutablePointer?, _ code: (SwiftObject) throws -> Value) -> SWRT_HResult { _implement(this) { - guard let value else { throw HResult.Error.pointer } + guard let value else { throw COMError.pointer } + value.pointee = try code($0) + } + } +} + +extension DelegateProjection { + // Shadow COMTwoWayProjection methods to use WinRTError instead of COMError + public static func _implement(_ this: UnsafeMutablePointer?, _ body: (SwiftObject) throws -> Void) -> SWRT_HResult { + guard let this else { return WinRTError.toABI(hresult: HResult.pointer, message: "WinRT 'this' pointer was null") } + let implementation: SwiftObject = COMEmbedding.getImplementationOrCrash(this) + return WinRTError.toABI { try body(implementation) } + } + + public static func _getter(_ this: ABIPointer?, _ value: UnsafeMutablePointer?, _ code: (SwiftObject) throws -> Value) -> SWRT_HResult { + _implement(this) { + guard let value else { throw COMError.pointer } + value.pointee = try code($0) + } + } +} + +extension ActivatableClassProjection { + // Shadow COMTwoWayProjection methods to use WinRTError instead of COMError + public static func _implement(_ this: UnsafeMutablePointer?, _ body: (SwiftObject) throws -> Void) -> SWRT_HResult { + guard let this else { return WinRTError.toABI(hresult: HResult.pointer, message: "WinRT 'this' pointer was null") } + let implementation: SwiftObject = COMEmbedding.getImplementationOrCrash(this) + return WinRTError.toABI { try body(implementation) } + } + + public static func _getter(_ this: ABIPointer?, _ value: UnsafeMutablePointer?, _ code: (SwiftObject) throws -> Value) -> SWRT_HResult { + _implement(this) { + guard let value else { throw COMError.pointer } value.pointee = try code($0) } } @@ -50,4 +92,18 @@ extension ComposableClassProjection { public static func _wrapObject(_ reference: consuming IInspectableReference) -> IInspectable { try! _wrap(reference.queryInterface(interfaceID)) as! IInspectable } + + // Shadow COMTwoWayProjection methods to use WinRTError instead of COMError + public static func _implement(_ this: UnsafeMutablePointer?, _ body: (SwiftObject) throws -> Void) -> SWRT_HResult { + guard let this else { return WinRTError.toABI(hresult: HResult.pointer, message: "WinRT 'this' pointer was null") } + let implementation: SwiftObject = COMEmbedding.getImplementationOrCrash(this) + return WinRTError.toABI { try body(implementation) } + } + + public static func _getter(_ this: ABIPointer?, _ value: UnsafeMutablePointer?, _ code: (SwiftObject) throws -> Value) -> SWRT_HResult { + _implement(this) { + guard let value else { throw COMError.pointer } + value.pointee = try code($0) + } + } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/HString.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/HString.swift index 5e1519e2..bbad6803 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/HString.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/HString.swift @@ -13,7 +13,7 @@ public struct HString: ~Copyable { public init(duplicating abi: WindowsRuntime_ABI.SWRT_HString?) throws { var duplicated: WindowsRuntime_ABI.SWRT_HString? - try HResult.throwIfFailed(WindowsRuntime_ABI.SWRT_WindowsDuplicateString(abi, &duplicated)) + try COMError.fromABI(WindowsRuntime_ABI.SWRT_WindowsDuplicateString(abi, &duplicated)) self.init(transferring: duplicated) } @@ -26,12 +26,12 @@ public struct HString: ~Copyable { var buffer: WindowsRuntime_ABI.SWRT_HStringBuffer? = nil var pointer: UnsafeMutablePointer? = nil let codeUnitCount = value.utf16.count - try HResult.throwIfFailed(WindowsRuntime_ABI.SWRT_WindowsPreallocateStringBuffer(UInt32(codeUnitCount), &pointer, &buffer)) - guard let pointer else { throw HResult.Error.pointer } + try COMError.fromABI(WindowsRuntime_ABI.SWRT_WindowsPreallocateStringBuffer(UInt32(codeUnitCount), &pointer, &buffer)) + guard let pointer else { throw COMError.pointer } _ = UnsafeMutableBufferPointer(start: pointer, count: codeUnitCount).initialize(from: value.utf16) var abi: WindowsRuntime_ABI.SWRT_HString? - do { try HResult.throwIfFailed(WindowsRuntime_ABI.SWRT_WindowsPromoteStringBuffer(buffer, &abi)) } + do { try COMError.fromABI(WindowsRuntime_ABI.SWRT_WindowsPromoteStringBuffer(buffer, &abi)) } catch { WindowsRuntime_ABI.SWRT_WindowsDeleteStringBuffer(buffer) throw error @@ -51,7 +51,7 @@ public struct HString: ~Copyable { public func duplicate() throws -> Self { var duplicated: WindowsRuntime_ABI.SWRT_HString? - try HResult.throwIfFailed(WindowsRuntime_ABI.SWRT_WindowsDuplicateString(abi, &duplicated)) + try COMError.fromABI(WindowsRuntime_ABI.SWRT_WindowsDuplicateString(abi, &duplicated)) return .init(transferring: duplicated) } diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IActivationFactory.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IActivationFactory.swift index 0fb39aae..960496e3 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IActivationFactory.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IActivationFactory.swift @@ -38,16 +38,16 @@ extension COMInterop where ABIStruct == WindowsRuntime_ABI.SWRT_IActivationFacto // Activation factory methods are special-cased to return the pointer. public func activateInstance() throws -> IInspectablePointer? { var instance = IInspectableProjection.abiDefaultValue - try WinRTError.throwIfFailed(this.pointee.VirtualTable.pointee.ActivateInstance(this, &instance)) + try WinRTError.fromABI(this.pointee.VirtualTable.pointee.ActivateInstance(this, &instance)) return instance } // TODO: Move elsewhere to keep COMInterop only for bridging. public func activateInstance(projection: Projection.Type) throws -> Projection.ABIPointer { var inspectable = IInspectableProjection.abiDefaultValue - try WinRTError.throwIfFailed(this.pointee.VirtualTable.pointee.ActivateInstance(this, &inspectable)) + try WinRTError.fromABI(this.pointee.VirtualTable.pointee.ActivateInstance(this, &inspectable)) defer { IInspectableProjection.release(&inspectable) } - guard let inspectable else { throw COM.HResult.Error.noInterface } + guard let inspectable else { throw COM.COMError.noInterface } return try COMInterop(inspectable) .queryInterface(projection.interfaceID, type: Projection.ABIStruct.self) .detach() diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IBufferByteAccess.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IBufferByteAccess.swift index 018399d0..5889f276 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IBufferByteAccess.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IBufferByteAccess.swift @@ -40,7 +40,7 @@ public func uuidof(_: WindowsRuntime_ABI.SWRT_IBufferByteAccess.Type) -> COMInte extension COMInterop where ABIStruct == WindowsRuntime_ABI.SWRT_IBufferByteAccess { public func buffer() throws -> UnsafeMutablePointer? { var value: UnsafeMutablePointer? = nil - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.Buffer(this, &value)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.Buffer(this, &value)) return value } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IInspectable.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IInspectable.swift index 082093dc..c2b80946 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IInspectable.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IInspectable.swift @@ -45,20 +45,20 @@ public typealias IInspectableReference = IInspectableProjection.ABIReference extension COMInterop where ABIStruct == WindowsRuntime_ABI.SWRT_IInspectable { public func getIids() throws -> [COMInterfaceID] { var iids: COMArray = .null - try WinRTError.throwIfFailed(this.pointee.VirtualTable.pointee.GetIids(this, &iids.count, &iids.pointer)) + try WinRTError.fromABI(this.pointee.VirtualTable.pointee.GetIids(this, &iids.count, &iids.pointer)) defer { iids.deallocate() } return ArrayProjection.toSwift(consuming: &iids) } public func getRuntimeClassName() throws -> String { var runtimeClassName: WindowsRuntime_ABI.SWRT_HString? - try WinRTError.throwIfFailed(this.pointee.VirtualTable.pointee.GetRuntimeClassName(this, &runtimeClassName)) + try WinRTError.fromABI(this.pointee.VirtualTable.pointee.GetRuntimeClassName(this, &runtimeClassName)) return StringProjection.toSwift(consuming: &runtimeClassName) } public func getTrustLevel() throws -> TrustLevel { var trustLevel: WindowsRuntime_ABI.SWRT_TrustLevel = 0 - try WinRTError.throwIfFailed(this.pointee.VirtualTable.pointee.GetTrustLevel(this, &trustLevel)) + try WinRTError.fromABI(this.pointee.VirtualTable.pointee.GetTrustLevel(this, &trustLevel)) return TrustLevel.toSwift(trustLevel) } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IMemoryBufferByteAccess.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IMemoryBufferByteAccess.swift index 8b228efe..44aa729f 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IMemoryBufferByteAccess.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IMemoryBufferByteAccess.swift @@ -31,7 +31,7 @@ public enum IMemoryBufferByteAccessProjection: COMTwoWayProjection { AddRef: { IUnknownVirtualTable.AddRef($0) }, Release: { IUnknownVirtualTable.Release($0) }, GetBuffer: { this, value, capacity in _implement(this) { this in - guard let value, let capacity else { throw HResult.Error.pointer } + guard let value, let capacity else { throw COMError.pointer } let buffer = try this.buffer value.pointee = buffer.baseAddress capacity.pointee = UInt32(buffer.count) @@ -46,7 +46,7 @@ extension COMInterop where ABIStruct == WindowsRuntime_ABI.SWRT_IMemoryBufferByt public func getBuffer() throws -> UnsafeMutableBufferPointer? { var value: UnsafeMutablePointer? = nil var capacity: UInt32 = 0 - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.GetBuffer(this, &value, &capacity)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.GetBuffer(this, &value, &capacity)) return UnsafeMutableBufferPointer(start: value, count: Int(capacity)) } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IRestrictedErrorInfo.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IRestrictedErrorInfo.swift index f9fd565f..97898993 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IRestrictedErrorInfo.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IRestrictedErrorInfo.swift @@ -77,7 +77,7 @@ extension COMInterop where ABIStruct == WindowsRuntime_ABI.SWRT_IRestrictedError defer { BStrProjection.release(&restrictedDescription_) } var capabilitySid_: WindowsRuntime_ABI.SWRT_BStr? = nil defer { BStrProjection.release(&capabilitySid_) } - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.GetErrorDetails(this, &description_, &error_, &restrictedDescription_, &capabilitySid_)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.GetErrorDetails(this, &description_, &error_, &restrictedDescription_, &capabilitySid_)) description = BStrProjection.toSwift(consuming: &description_) error = HResultProjection.toSwift(error_) restrictedDescription = BStrProjection.toSwift(consuming: &restrictedDescription_) @@ -86,7 +86,7 @@ extension COMInterop where ABIStruct == WindowsRuntime_ABI.SWRT_IRestrictedError public func getReference() throws -> String? { var value = BStrProjection.abiDefaultValue - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.GetReference(this, &value)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.GetReference(this, &value)) return BStrProjection.toSwift(consuming: &value) } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IWeakReference.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IWeakReference.swift index 3665ff51..690dd750 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IWeakReference.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IWeakReference.swift @@ -31,7 +31,7 @@ public enum IWeakReferenceProjection: COMTwoWayProjection { AddRef: { IUnknownVirtualTable.AddRef($0) }, Release: { IUnknownVirtualTable.Release($0) }, Resolve: { this, iid, objectReference in _implement(this) { - guard let iid, let objectReference else { throw HResult.Error.pointer } + guard let iid, let objectReference else { throw COMError.pointer } objectReference.pointee = nil var inspectable = try IInspectableProjection.toABI($0.resolve()) defer { IInspectableProjection.release(&inspectable) } @@ -50,7 +50,7 @@ extension COMInterop where ABIStruct == WindowsRuntime_ABI.SWRT_IWeakReference { public func resolve(_ iid: COMInterfaceID) throws -> IInspectable? { var iid = GUIDProjection.toABI(iid) var objectReference = IInspectableProjection.abiDefaultValue - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.Resolve(this, &iid, &objectReference)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.Resolve(this, &iid, &objectReference)) return IInspectableProjection.toSwift(consuming: &objectReference) } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IWeakReferenceSource.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IWeakReferenceSource.swift index b58b658c..cee8dc2d 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IWeakReferenceSource.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/Core/IWeakReferenceSource.swift @@ -40,7 +40,7 @@ public func uuidof(_: WindowsRuntime_ABI.SWRT_IWeakReferenceSource.Type) -> COMI extension COMInterop where ABIStruct == WindowsRuntime_ABI.SWRT_IWeakReferenceSource { public func getWeakReference() throws -> IWeakReference? { var value = IWeakReferenceProjection.abiDefaultValue - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.GetWeakReference(this, &value)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.GetWeakReference(this, &value)) return IWeakReferenceProjection.toSwift(consuming: &value) } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IPropertyValue.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IPropertyValue.swift index 40948031..50459cb7 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IPropertyValue.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IPropertyValue.swift @@ -52,43 +52,43 @@ extension WindowsFoundation_IPropertyValueProtocol { public var type: WindowsFoundation_PropertyType { try! _type() } public var isNumericScalar: Bool { try! _isNumericScalar() } - public func getUInt8() throws -> UInt8 { throw HResult.Error.notImpl } - public func getInt16() throws -> Int16 { throw HResult.Error.notImpl } - public func getUInt16() throws -> UInt16 { throw HResult.Error.notImpl } - public func getInt32() throws -> Int32 { throw HResult.Error.notImpl } - public func getUInt32() throws -> UInt32 { throw HResult.Error.notImpl } - public func getInt64() throws -> Int64 { throw HResult.Error.notImpl } - public func getUInt64() throws -> UInt64 { throw HResult.Error.notImpl } - public func getSingle() throws -> Float { throw HResult.Error.notImpl } - public func getDouble() throws -> Double { throw HResult.Error.notImpl } - public func getChar16() throws -> Char16 { throw HResult.Error.notImpl } - public func getBoolean() throws -> Bool { throw HResult.Error.notImpl } - public func getString() throws -> String { throw HResult.Error.notImpl } - public func getGuid() throws -> GUID { throw HResult.Error.notImpl } - public func getDateTime() throws -> WindowsFoundation_DateTime { throw HResult.Error.notImpl } - public func getTimeSpan() throws -> WindowsFoundation_TimeSpan { throw HResult.Error.notImpl } - public func getPoint() throws -> WindowsFoundation_Point { throw HResult.Error.notImpl } - public func getSize() throws -> WindowsFoundation_Size { throw HResult.Error.notImpl } - public func getRect() throws -> WindowsFoundation_Rect { throw HResult.Error.notImpl } - public func getUInt8Array(_ value: inout [UInt8]) throws { throw HResult.Error.notImpl } - public func getInt16Array(_ value: inout [Int16]) throws { throw HResult.Error.notImpl } - public func getUInt16Array(_ value: inout [UInt16]) throws { throw HResult.Error.notImpl } - public func getInt32Array(_ value: inout [Int32]) throws { throw HResult.Error.notImpl } - public func getUInt32Array(_ value: inout [UInt32]) throws { throw HResult.Error.notImpl } - public func getInt64Array(_ value: inout [Int64]) throws { throw HResult.Error.notImpl } - public func getUInt64Array(_ value: inout [UInt64]) throws { throw HResult.Error.notImpl } - public func getSingleArray(_ value: inout [Float]) throws { throw HResult.Error.notImpl } - public func getDoubleArray(_ value: inout [Double]) throws { throw HResult.Error.notImpl } - public func getChar16Array(_ value: inout [Char16]) throws { throw HResult.Error.notImpl } - public func getBooleanArray(_ value: inout [Bool]) throws { throw HResult.Error.notImpl } - public func getStringArray(_ value: inout [String]) throws { throw HResult.Error.notImpl } - public func getInspectableArray(_ value: inout [IInspectable?]) throws { throw HResult.Error.notImpl } - public func getGuidArray(_ value: inout [GUID]) throws { throw HResult.Error.notImpl } - public func getDateTimeArray(_ value: inout [WindowsFoundation_DateTime]) throws { throw HResult.Error.notImpl } - public func getTimeSpanArray(_ value: inout [WindowsFoundation_TimeSpan]) throws { throw HResult.Error.notImpl } - public func getPointArray(_ value: inout [WindowsFoundation_Point]) throws { throw HResult.Error.notImpl } - public func getSizeArray(_ value: inout [WindowsFoundation_Size]) throws { throw HResult.Error.notImpl } - public func getRectArray(_ value: inout [WindowsFoundation_Rect]) throws { throw HResult.Error.notImpl } + public func getUInt8() throws -> UInt8 { throw COMError.notImpl } + public func getInt16() throws -> Int16 { throw COMError.notImpl } + public func getUInt16() throws -> UInt16 { throw COMError.notImpl } + public func getInt32() throws -> Int32 { throw COMError.notImpl } + public func getUInt32() throws -> UInt32 { throw COMError.notImpl } + public func getInt64() throws -> Int64 { throw COMError.notImpl } + public func getUInt64() throws -> UInt64 { throw COMError.notImpl } + public func getSingle() throws -> Float { throw COMError.notImpl } + public func getDouble() throws -> Double { throw COMError.notImpl } + public func getChar16() throws -> Char16 { throw COMError.notImpl } + public func getBoolean() throws -> Bool { throw COMError.notImpl } + public func getString() throws -> String { throw COMError.notImpl } + public func getGuid() throws -> GUID { throw COMError.notImpl } + public func getDateTime() throws -> WindowsFoundation_DateTime { throw COMError.notImpl } + public func getTimeSpan() throws -> WindowsFoundation_TimeSpan { throw COMError.notImpl } + public func getPoint() throws -> WindowsFoundation_Point { throw COMError.notImpl } + public func getSize() throws -> WindowsFoundation_Size { throw COMError.notImpl } + public func getRect() throws -> WindowsFoundation_Rect { throw COMError.notImpl } + public func getUInt8Array(_ value: inout [UInt8]) throws { throw COMError.notImpl } + public func getInt16Array(_ value: inout [Int16]) throws { throw COMError.notImpl } + public func getUInt16Array(_ value: inout [UInt16]) throws { throw COMError.notImpl } + public func getInt32Array(_ value: inout [Int32]) throws { throw COMError.notImpl } + public func getUInt32Array(_ value: inout [UInt32]) throws { throw COMError.notImpl } + public func getInt64Array(_ value: inout [Int64]) throws { throw COMError.notImpl } + public func getUInt64Array(_ value: inout [UInt64]) throws { throw COMError.notImpl } + public func getSingleArray(_ value: inout [Float]) throws { throw COMError.notImpl } + public func getDoubleArray(_ value: inout [Double]) throws { throw COMError.notImpl } + public func getChar16Array(_ value: inout [Char16]) throws { throw COMError.notImpl } + public func getBooleanArray(_ value: inout [Bool]) throws { throw COMError.notImpl } + public func getStringArray(_ value: inout [String]) throws { throw COMError.notImpl } + public func getInspectableArray(_ value: inout [IInspectable?]) throws { throw COMError.notImpl } + public func getGuidArray(_ value: inout [GUID]) throws { throw COMError.notImpl } + public func getDateTimeArray(_ value: inout [WindowsFoundation_DateTime]) throws { throw COMError.notImpl } + public func getTimeSpanArray(_ value: inout [WindowsFoundation_TimeSpan]) throws { throw COMError.notImpl } + public func getPointArray(_ value: inout [WindowsFoundation_Point]) throws { throw COMError.notImpl } + public func getSizeArray(_ value: inout [WindowsFoundation_Size]) throws { throw COMError.notImpl } + public func getRectArray(_ value: inout [WindowsFoundation_Rect]) throws { throw COMError.notImpl } } import SWRT_WindowsFoundation @@ -100,13 +100,13 @@ internal func uuidof(_: SWRT_WindowsFoundation_IPropertyValue.Type) -> COMInterf extension COMInterop where ABIStruct == SWRT_WindowsFoundation_IPropertyValue { internal func get_Type() throws -> WindowsFoundation_PropertyType { var abi_value: SWRT_WindowsFoundation_PropertyType = .init() - try WinRTError.throwIfFailed(this.pointee.VirtualTable.pointee.get_Type(this, &abi_value)) + try WinRTError.fromABI(this.pointee.VirtualTable.pointee.get_Type(this, &abi_value)) fatalError("Not implemented") } internal func get_IsNumericScalar() throws -> Bool { var abi_value: CBool = false - try WinRTError.throwIfFailed(this.pointee.VirtualTable.pointee.get_IsNumericScalar(this, &abi_value)) + try WinRTError.fromABI(this.pointee.VirtualTable.pointee.get_IsNumericScalar(this, &abi_value)) return abi_value } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IReference.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IReference.swift index b367dd47..1d9da005 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IReference.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IReference.swift @@ -92,15 +92,15 @@ fileprivate var virtualTable: SWRT_WindowsFoundation_IReference_VirtualTable = GetRuntimeClassName: { IInspectableVirtualTable.GetRuntimeClassName($0, $1) }, GetTrustLevel: { IInspectableVirtualTable.GetTrustLevel($0, $1) }, get_Value: { this, value in - guard let this, let value else { return HResult.invalidArg.value } + guard let this, let value else { return WinRTError.toABI(hresult: HResult.invalidArg) } guard let reference: any WindowsFoundation_IReferenceProtocolABI = COMEmbedding.getImplementation(this) else { - return HResult.fail.value + return WinRTError.toABI(hresult: HResult.fail, message: "Swift object should implement IReferenceProtocolABI") } - return HResult.catch { try reference._getABIValue(value) }.value + return WinRTError.toABI { try reference._getABIValue(value) } }) extension COMInterop where ABIStruct == SWRT_WindowsFoundation_IReference { public func get_Value(_ value: UnsafeMutableRawPointer) throws { - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.get_Value(this, value)) + try WinRTError.fromABI(this.pointee.VirtualTable.pointee.get_Value(this, value)) } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IReferenceArray.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IReferenceArray.swift index f56ce453..f45307df 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IReferenceArray.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IReferenceArray.swift @@ -89,15 +89,15 @@ fileprivate var virtualTable: SWRT_WindowsFoundation_IReferenceArray_VirtualTabl GetRuntimeClassName: { IInspectableVirtualTable.GetRuntimeClassName($0, $1) }, GetTrustLevel: { IInspectableVirtualTable.GetTrustLevel($0, $1) }, get_Value: { this, length, pointer in - guard let this, let length, let pointer else { return HResult.invalidArg.value } + guard let this, let length, let pointer else { return WinRTError.toABI(hresult: HResult.invalidArg) } guard let reference: any WindowsFoundation_IReferenceArrayProtocolABI = COMEmbedding.getImplementation(this) else { - return HResult.fail.value + return WinRTError.toABI(hresult: HResult.fail, message: "Swift object should implement IReferenceArrayProtocolABI") } - return HResult.catch { try reference._getABIValue(&length.pointee, &pointer.pointee) }.value + return WinRTError.toABI { try reference._getABIValue(&length.pointee, &pointer.pointee) } }) extension COMInterop where ABIStruct == SWRT_WindowsFoundation_IReferenceArray { public func get_Value(_ length: inout UInt32, _ pointer: inout UnsafeMutableRawPointer?) throws { - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.get_Value(this, &length, &pointer)) + try WinRTError.fromABI(this.pointee.VirtualTable.pointee.get_Value(this, &length, &pointer)) } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IStringable.swift b/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IStringable.swift index 3f9e32f7..cc801dda 100644 --- a/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IStringable.swift +++ b/Support/Sources/WindowsRuntime/ProjectedTypes/WindowsFoundation/WindowsFoundation_IStringable.swift @@ -48,7 +48,7 @@ public func uuidof(_: SWRT_WindowsFoundation_IStringable.Type) -> COMInterfaceID extension COMInterop where ABIStruct == SWRT_WindowsFoundation_IStringable { public func toString() throws -> String { var value = StringProjection.abiDefaultValue - try HResult.throwIfFailed(this.pointee.VirtualTable.pointee.ToString(this, &value)) + try COMError.fromABI(this.pointee.VirtualTable.pointee.ToString(this, &value)) return StringProjection.toSwift(consuming: &value) } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/PropertyValueStatics.swift b/Support/Sources/WindowsRuntime/PropertyValueStatics.swift index 5417099b..62b44223 100644 --- a/Support/Sources/WindowsRuntime/PropertyValueStatics.swift +++ b/Support/Sources/WindowsRuntime/PropertyValueStatics.swift @@ -211,8 +211,8 @@ internal enum PropertyValueStatics { private static func create(_ value: ABIValue, factory: SingleValueFactory) throws -> COMReference { var propertyValue: IInspectablePointer? = nil - try WinRTError.throwIfFailed(factory(this, value, &propertyValue)) - guard let propertyValue else { throw HResult.Error.pointer } + try WinRTError.fromABI(factory(this, value, &propertyValue)) + guard let propertyValue else { throw COMError.pointer } return COMReference(transferringRef: propertyValue) } @@ -223,8 +223,8 @@ internal enum PropertyValueStatics { var value_abi = try projection.toABI(value) defer { projection.release(&value_abi) } var propertyValue: IInspectablePointer? = nil - try WinRTError.throwIfFailed(factory(this, value_abi, &propertyValue)) - guard let propertyValue else { throw HResult.Error.pointer } + try WinRTError.fromABI(factory(this, value_abi, &propertyValue)) + guard let propertyValue else { throw COMError.pointer } return COMReference(transferringRef: propertyValue) } @@ -247,16 +247,16 @@ internal enum PropertyValueStatics { if inertProjection, MemoryLayout.size == MemoryLayout.size { try value.withUnsafeBufferPointer { bufferPointer in let abiPointer = bufferPointer.baseAddress.map { UnsafePointer(OpaquePointer($0)) } - try WinRTError.throwIfFailed(factory(this, UInt32(bufferPointer.count), UnsafeMutablePointer(mutating: abiPointer), &propertyValue)) + try WinRTError.fromABI(factory(this, UInt32(bufferPointer.count), UnsafeMutablePointer(mutating: abiPointer), &propertyValue)) } } else { var value_abi = try ArrayProjection.toABI(value) defer { ArrayProjection.release(&value_abi) } - try WinRTError.throwIfFailed(factory(this, value_abi.count, value_abi.pointer, &propertyValue)) + try WinRTError.fromABI(factory(this, value_abi.count, value_abi.pointer, &propertyValue)) } - guard let propertyValue else { throw HResult.Error.pointer } + guard let propertyValue else { throw COMError.pointer } return COMReference(transferringRef: propertyValue) } diff --git a/Support/Sources/WindowsRuntime/SwiftRestrictedErrorInfo.swift b/Support/Sources/WindowsRuntime/SwiftRestrictedErrorInfo.swift new file mode 100644 index 00000000..34c7f8e3 --- /dev/null +++ b/Support/Sources/WindowsRuntime/SwiftRestrictedErrorInfo.swift @@ -0,0 +1,36 @@ +import COM + +// Wraps a Swift Error object into an `IRestrictedErrorInfo` to preserve it across WinRT boundaries. +public class SwiftRestrictedErrorInfo: SwiftErrorInfo, IRestrictedErrorInfoProtocol { + public override class var implements: [COMImplements] { [ + .init(IRestrictedErrorInfoProjection.self) + ] } + + public override init(error: Error) { + super.init(error: error) + } + + public func originate(captureContext: Bool) { + WinRTError.originate(hresult: hresult, message: description, restrictedErrorInfo: self) + if captureContext { try? WinRTError.captureContext(hresult: hresult) } + } + + public override func toABI(setErrorInfo: Bool = true) -> HResult.Value { + if setErrorInfo { try? WinRTError.setRestrictedErrorInfo(self) } + return hresult.value + } + + // IRestrictedErrorInfo + public func getErrorDetails( + description: inout String?, + error: inout HResult, + restrictedDescription: inout String?, + capabilitySid: inout String?) throws { + description = self.description + error = self.hresult + restrictedDescription = description + capabilitySid = nil + } + + public var reference: String? { get throws { throw COMError.fail } } +} \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/WeakReference.swift b/Support/Sources/WindowsRuntime/WeakReference.swift index 38f08785..6ed993d1 100644 --- a/Support/Sources/WindowsRuntime/WeakReference.swift +++ b/Support/Sources/WindowsRuntime/WeakReference.swift @@ -6,7 +6,7 @@ public final class WeakReference { private var weakReference: COMReference public init(_ target: Projection.SwiftObject) throws { - guard let targetInspectable = target as? IInspectable else { throw HResult.Error.invalidArg } + guard let targetInspectable = target as? IInspectable else { throw COMError.invalidArg } let source = try targetInspectable._queryInterface( uuidof(SWRT_IWeakReferenceSource.self), type: SWRT_IWeakReferenceSource.self) self.weakReference = .init(transferringRef: try Self.getWeakReference(source.pointer)) @@ -17,15 +17,15 @@ public final class WeakReference { _ source: UnsafeMutablePointer) throws -> UnsafeMutablePointer { var weakReference: UnsafeMutablePointer? - try WinRTError.throwIfFailed(source.pointee.VirtualTable.pointee.GetWeakReference(source, &weakReference)) + try WinRTError.fromABI(source.pointee.VirtualTable.pointee.GetWeakReference(source, &weakReference)) if let weakReference { return weakReference } - throw HResult.Error.fail + throw COMError.fail } public func resolve() throws -> Projection.SwiftObject? { var inspectableTarget: UnsafeMutablePointer? = nil var iid = GUIDProjection.toABI(Projection.interfaceID) - try WinRTError.throwIfFailed(weakReference.pointer.pointee.VirtualTable.pointee.Resolve( + try WinRTError.fromABI(weakReference.pointer.pointee.VirtualTable.pointee.Resolve( weakReference.pointer, &iid, &inspectableTarget)) var target = Projection.ABIPointer(OpaquePointer(inspectableTarget)) return Projection.toSwift(consuming: &target) diff --git a/Support/Sources/WindowsRuntime/WinRTError.swift b/Support/Sources/WindowsRuntime/WinRTError.swift index 3833c06b..747a4502 100644 --- a/Support/Sources/WindowsRuntime/WinRTError.swift +++ b/Support/Sources/WindowsRuntime/WinRTError.swift @@ -1,60 +1,161 @@ import COM import WindowsRuntime_ABI -public struct WinRTError: COMError, CustomStringConvertible { +/// Captures a failure from a WinRT API invocation (HRESULT + optional IRestrictedErrorInfo). +/// This error object only differs from COMError in that it relies on `IRestrictedErrorInfo` for the message. +/// Also exposes WinRT error APIs as static members. +public struct WinRTError: COMErrorProtocol, CustomStringConvertible { public let hresult: HResult - public let errorInfo: IRestrictedErrorInfo? + public let restrictedErrorInfo: IRestrictedErrorInfo? - public init?(hresult: HResult, captureErrorInfo: Bool) { - if hresult.isSuccess { return nil } + public init(hresult: HResult, errorInfo: IRestrictedErrorInfo? = nil) { + assert(hresult.isFailure) self.hresult = hresult - self.errorInfo = captureErrorInfo ? try? Self.getRestrictedErrorInfo(matching: hresult) : nil + self.restrictedErrorInfo = errorInfo + } + + public init(hresult: HResult, message: String?) { + self.init(hresult: hresult, errorInfo: message.map { MessageRestrictedErrorInfo(hresult: hresult, message: $0) }) + } + + public var errorInfo: IErrorInfo? { + try? restrictedErrorInfo?.queryInterface(IErrorInfoProjection.self) } public var description: String { - let details = (try? errorInfo?.details) ?? RestrictedErrorInfoDetails() + let details = (try? restrictedErrorInfo?.details) ?? RestrictedErrorInfoDetails() // RestrictedDescription contains the value reported in RoOriginateError return details.restrictedDescription ?? details.description ?? hresult.description } - public static func throwIfFailed(_ hresult: WindowsRuntime_ABI.SWRT_HResult) throws { - let hresult = HResultProjection.toSwift(hresult) - guard let error = WinRTError(hresult: hresult, captureErrorInfo: true) else { return } - throw error + public func toABI(setErrorInfo: Bool = true) -> HResult.Value { + if setErrorInfo { try? Self.setRestrictedErrorInfo(restrictedErrorInfo) } + return hresult.value } - public static func catchAndOriginate(_ body: () throws -> Void) -> WindowsRuntime_ABI.SWRT_HResult { - do { - try body() - return HResult.ok.value - } - catch let error { - let hresult = (error as? COMError)?.hresult ?? HResult.fail - var message = (try? StringProjection.toABI(error.localizedDescription)) ?? nil - defer { StringProjection.release(&message) } - WindowsRuntime_ABI.SWRT_RoOriginateError(hresult.value, message) - return hresult.value + /// Throws any failure HRESULTs as WinRTErrors, optionally capturing the WinRT thread error info. + @discardableResult + public static func fromABI(captureErrorInfo: Bool = true, _ hresult: WindowsRuntime_ABI.SWRT_HResult) throws -> HResult { + let hresult = HResult(hresult) + guard hresult.isFailure else { return hresult } + guard captureErrorInfo else { throw WinRTError(hresult: hresult) } + + let restrictedErrorInfo = try? Self.getRestrictedErrorInfo(matching: hresult) + if let swiftErrorInfo = restrictedErrorInfo as? SwiftRestrictedErrorInfo, swiftErrorInfo.hresult == hresult { + // This was originally a Swift error, throw it as such. + throw swiftErrorInfo.error } + + throw WinRTError(hresult: hresult, errorInfo: restrictedErrorInfo) + } + + /// Catches any thrown errors from a provided closure, converting it to an HRESULT and setting the WinRT error info state. + public static func toABI(originate: Bool = true, captureContext: Bool = true, _ body: () throws -> Void) -> HResult.Value { + do { try body() } + catch { return toABI(error: error, originate: originate, captureContext: captureContext) } + return HResult.ok.value + } + + public static func toABI(error: Error, originate: Bool = true, captureContext: Bool = true) -> HResult.Value { + // If the error already came from COM/WinRT, propagate it + if let comError = error as? any COMErrorProtocol { return comError.toABI() } + + // Otherwise, originate a new error + let restrictedErrorInfo = SwiftRestrictedErrorInfo(error: error) + if originate { restrictedErrorInfo.originate(captureContext: captureContext) } + return restrictedErrorInfo.hresult.value + } + + public static func toABI(hresult: HResult, message: String? = nil, captureContext: Bool = true) -> HResult.Value { + guard hresult.isFailure else { return hresult.value } + Self.originate(hresult: hresult, message: message) + if captureContext { try? Self.captureContext(hresult: hresult) } + return hresult.value + } + + @discardableResult + public static func originate(hresult: HResult, message: String?) -> Bool { + var message = message == nil ? nil : try? StringProjection.toABI(message!) + defer { StringProjection.release(&message) } + return WindowsRuntime_ABI.SWRT_RoOriginateError(hresult.value, message) + } + + @discardableResult + public static func originate(hresult: HResult, message: String?, restrictedErrorInfo: IRestrictedErrorInfo?) -> Bool { + guard let restrictedErrorInfo else { return originate(hresult: hresult, message: message) } + + var message = message == nil ? nil : try? StringProjection.toABI(message!) + defer { StringProjection.release(&message) } + var iunknown = try? IUnknownProjection.toABI(restrictedErrorInfo) + defer { IUnknownProjection.release(&iunknown) } + return WindowsRuntime_ABI.SWRT_RoOriginateLanguageException(hresult.value, message, iunknown) + } + + public static func clear() { + WindowsRuntime_ABI.SWRT_RoClearError() + } + + public static func captureContext(hresult: HResult) throws { + try COMError.fromABI(SWRT_RoCaptureErrorContext(hresult.value)) + } + + public static func failFastWithContext(hresult: HResult) throws { + SWRT_RoFailFastWithErrorContext(hresult.value) } public static func getRestrictedErrorInfo() throws -> IRestrictedErrorInfo? { var restrictedErrorInfo: UnsafeMutablePointer? defer { IRestrictedErrorInfoProjection.release(&restrictedErrorInfo) } - - // Don't throw a WinRTError, that would be recursive - let hresult = WindowsRuntime_ABI.SWRT_GetRestrictedErrorInfo(&restrictedErrorInfo) - if let error = WinRTError(hresult: HResult(hresult), captureErrorInfo: false) { throw error } - + try fromABI(captureErrorInfo: false, WindowsRuntime_ABI.SWRT_GetRestrictedErrorInfo(&restrictedErrorInfo)) return IRestrictedErrorInfoProjection.toSwift(consuming: &restrictedErrorInfo) } public static func getRestrictedErrorInfo(matching expectedHResult: HResult) throws -> IRestrictedErrorInfo? { var restrictedErrorInfo: UnsafeMutablePointer? defer { IRestrictedErrorInfoProjection.release(&restrictedErrorInfo) } + try fromABI(captureErrorInfo: false, WindowsRuntime_ABI.SWRT_RoGetMatchingRestrictedErrorInfo(expectedHResult.value, &restrictedErrorInfo)) + return IRestrictedErrorInfoProjection.toSwift(consuming: &restrictedErrorInfo) + } - let hresult = WindowsRuntime_ABI.SWRT_RoGetMatchingRestrictedErrorInfo(expectedHResult.value, &restrictedErrorInfo) - if let error = WinRTError(hresult: HResult(hresult), captureErrorInfo: false) { throw error } + public static func setRestrictedErrorInfo(_ value: IRestrictedErrorInfo?) throws { + var abiValue = try IRestrictedErrorInfoProjection.toABI(value) + defer { IRestrictedErrorInfoProjection.release(&abiValue) } + try fromABI(captureErrorInfo: false, WindowsRuntime_ABI.SWRT_SetRestrictedErrorInfo(abiValue)) + } - return IRestrictedErrorInfoProjection.toSwift(consuming: &restrictedErrorInfo) + private final class MessageRestrictedErrorInfo: COMPrimaryExport, + IRestrictedErrorInfoProtocol, IErrorInfoProtocol { + public override class var implements: [COMImplements] { [ + .init(IErrorInfoProjection.self) + ] } + + public let hresult: HResult + public let message: String + + public init(hresult: HResult, message: String) { + self.hresult = hresult + self.message = message + } + + // IErrorInfo + public var guid: GUID { get throws { throw COMError.fail } } + public var source: String? { get throws { throw COMError.fail } } + public var description: String? { self.message } + public var helpFile: String? { get throws { throw COMError.fail } } + public var helpContext: UInt32 { get throws { throw COMError.fail } } + + // IRestrictedErrorInfo + public func getErrorDetails( + description: inout String?, + error: inout HResult, + restrictedDescription: inout String?, + capabilitySid: inout String?) throws { + description = self.message + error = self.hresult + restrictedDescription = self.message + capabilitySid = nil + } + + public var reference: String? { get throws { throw COMError.fail } } } } \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime_ABI/include/SWRT/windows/roerrorapi.h b/Support/Sources/WindowsRuntime_ABI/include/SWRT/windows/roerrorapi.h index 0a153795..d194813b 100644 --- a/Support/Sources/WindowsRuntime_ABI/include/SWRT/windows/roerrorapi.h +++ b/Support/Sources/WindowsRuntime_ABI/include/SWRT/windows/roerrorapi.h @@ -1,11 +1,28 @@ #pragma once #include +#include "SWRT/windows/unknwn.h" #include "SWRT/windows/restrictederrorinfo.h" #include "SWRT/windows/winstring.h" +typedef enum { + SWRT_RO_ERROR_REPORTING_NONE = 0x00000000, + SWRT_RO_ERROR_REPORTING_SUPPRESSEXCEPTIONS = 0x00000001, + SWRT_RO_ERROR_REPORTING_FORCEEXCEPTIONS = 0x00000002, + SWRT_RO_ERROR_REPORTING_USESETERRORINFO = 0x00000004, + SWRT_RO_ERROR_REPORTING_SUPPRESSSETERRORINFO = 0x00000008, +} SWRT_RO_ERROR_REPORTING_FLAGS; + SWRT_HResult SWRT_GetRestrictedErrorInfo(SWRT_IRestrictedErrorInfo** ppRestrictedErrorInfo); +SWRT_HResult SWRT_RoCaptureErrorContext(SWRT_HResult hr); void SWRT_RoClearError(); +void SWRT_RoFailFastWithErrorContext(SWRT_HResult hrError); +SWRT_HResult SWRT_RoGetErrorReportingFlags(uint32_t* pflags); SWRT_HResult SWRT_RoGetMatchingRestrictedErrorInfo(SWRT_HResult hrIn, SWRT_IRestrictedErrorInfo** ppRestrictedErrorInfo); bool SWRT_RoOriginateError(SWRT_HResult error, SWRT_HString message); -bool SWRT_RoOriginateErrorW(SWRT_HResult error, uint32_t cchMax, const char16_t* message); \ No newline at end of file +bool SWRT_RoOriginateErrorW(SWRT_HResult error, uint32_t cchMax, const char16_t* message); +bool SWRT_RoOriginateLanguageException(SWRT_HResult error, SWRT_HString message, SWRT_IUnknown* languageException); +SWRT_HResult SWRT_RoReportUnhandledError(SWRT_IRestrictedErrorInfo* pRestrictedErrorInfo); +SWRT_HResult SWRT_RoSetErrorReportingFlags(uint32_t flags); +SWRT_HResult SWRT_RoTransformError(SWRT_HResult oldError, SWRT_HResult newError, SWRT_HString message); +SWRT_HResult SWRT_SetRestrictedErrorInfo(SWRT_IRestrictedErrorInfo* pRestrictedErrorInfo); \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime_ABI/roerrorapi.c b/Support/Sources/WindowsRuntime_ABI/roerrorapi.c index 9e7148a5..d54b82a4 100644 --- a/Support/Sources/WindowsRuntime_ABI/roerrorapi.c +++ b/Support/Sources/WindowsRuntime_ABI/roerrorapi.c @@ -7,10 +7,22 @@ SWRT_HResult SWRT_GetRestrictedErrorInfo(SWRT_IRestrictedErrorInfo** ppRestricte return (SWRT_HResult)GetRestrictedErrorInfo((IRestrictedErrorInfo**)ppRestrictedErrorInfo); } +SWRT_HResult SWRT_RoCaptureErrorContext(SWRT_HResult hr) { + return (SWRT_HResult)RoCaptureErrorContext((HRESULT)hr); +} + void SWRT_RoClearError() { RoClearError(); } +void SWRT_RoFailFastWithErrorContext(SWRT_HResult hrError) { + RoFailFastWithErrorContext((HRESULT)hrError); +} + +SWRT_HResult SWRT_RoGetErrorReportingFlags(uint32_t* pflags) { + return (SWRT_HResult)RoGetErrorReportingFlags(pflags); +} + SWRT_HResult SWRT_RoGetMatchingRestrictedErrorInfo(SWRT_HResult hrIn, SWRT_IRestrictedErrorInfo** ppRestrictedErrorInfo) { return (SWRT_HResult)RoGetMatchingRestrictedErrorInfo((HRESULT)hrIn, (IRestrictedErrorInfo**)ppRestrictedErrorInfo); } @@ -21,4 +33,24 @@ bool SWRT_RoOriginateError(SWRT_HResult error, SWRT_HString message) { bool SWRT_RoOriginateErrorW(SWRT_HResult error, uint32_t cchMax, const char16_t* message) { return RoOriginateErrorW((HRESULT)error, (UINT)cchMax, (PCWSTR)message); +} + +bool SWRT_RoOriginateLanguageException(SWRT_HResult error, SWRT_HString message, SWRT_IUnknown* languageException) { + return RoOriginateLanguageException((HRESULT)error, (HSTRING)message, (IUnknown*)languageException); +} + +SWRT_HResult SWRT_RoReportUnhandledError(SWRT_IRestrictedErrorInfo* pRestrictedErrorInfo) { + return (SWRT_HResult)RoReportUnhandledError((IRestrictedErrorInfo*)pRestrictedErrorInfo); +} + +SWRT_HResult SWRT_RoSetErrorReportingFlags(uint32_t flags) { + return (SWRT_HResult)RoSetErrorReportingFlags(flags); +} + +SWRT_HResult SWRT_RoTransformError(SWRT_HResult oldError, SWRT_HResult newError, SWRT_HString message) { + return (SWRT_HResult)RoTransformError((HRESULT)oldError, (HRESULT)newError, (HSTRING)message); +} + +SWRT_HResult SWRT_SetRestrictedErrorInfo(SWRT_IRestrictedErrorInfo* pRestrictedErrorInfo) { + return (SWRT_HResult)SetRestrictedErrorInfo((IRestrictedErrorInfo*)pRestrictedErrorInfo); } \ No newline at end of file