Skip to content

Commit

Permalink
Implement ISupportErrorInfo (#445)
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanlabelle authored Dec 26, 2024
1 parent e178fce commit 0c93b3e
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 6 deletions.
6 changes: 3 additions & 3 deletions Support/Sources/COM/COMDelegatingTearOff.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import COM_ABI
public final class COMDelegatingTearOff: COMEmbedderEx {
private var comEmbedding: COMEmbedding

public init(virtualTable: UnsafeRawPointer, owner: IUnknown) {
public init(owner: IUnknown, virtualTable: UnsafeRawPointer) {
comEmbedding = .init(virtualTable: virtualTable, owner: nil)
super.init(implementer: owner)
comEmbedding.initOwner(self)
}

public convenience init<Binding: COMTwoWayBinding>(binding: Binding.Type, owner: Binding.SwiftObject) {
self.init(virtualTable: Binding.virtualTablePointer, owner: owner as! IUnknown)
public convenience init<Binding: COMTwoWayBinding>(owner: Binding.SwiftObject, binding: Binding.Type) {
self.init(owner: owner as! IUnknown, virtualTable: Binding.virtualTablePointer)
}

public func toCOM() -> IUnknownReference { comEmbedding.toCOM() }
Expand Down
5 changes: 4 additions & 1 deletion Support/Sources/COM/COMExportBase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ open class COMExportBase<PrimaryInterfaceBinding: COMTwoWayBinding>: IUnknownPro
open class var queriableInterfaces: [any COMTwoWayBinding.Type] { [] }
open class var implementIAgileObject: Bool { true }
open class var implementFreeThreadedMarshaling: Bool { implementIAgileObject }
open class var implementISupportErrorInfo: Bool { true }

/// The COM identity object exposing the implementation of the primary interface.
private var primaryImplements: COMImplements<PrimaryInterfaceBinding> = .init()
Expand All @@ -24,9 +25,11 @@ open class COMExportBase<PrimaryInterfaceBinding: COMTwoWayBinding>: IUnknownPro
return toCOM().cast()
case FreeThreadedMarshalBinding.interfaceID where Self.implementFreeThreadedMarshaling:
return try FreeThreadedMarshal(self).toCOM().cast()
case ISupportErrorInfoBinding.interfaceID where Self.implementISupportErrorInfo:
return SupportErrorInfoForAllInterfaces(owner: self).toCOM().cast()
default:
if let interfaceBinding = Self.queriableInterfaces.first(where: { $0.interfaceID == id }) {
return COMDelegatingTearOff(virtualTable: interfaceBinding.virtualTablePointer, owner: self).toCOM()
return COMDelegatingTearOff(owner: self, virtualTable: interfaceBinding.virtualTablePointer).toCOM()
}
throw COMError.noInterface
}
Expand Down
47 changes: 47 additions & 0 deletions Support/Sources/COM/Projection/ISupportErrorInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import COM_ABI

public typealias ISupportErrorInfo = any ISupportErrorInfoProtocol
public protocol ISupportErrorInfoProtocol: IUnknownProtocol {
func interfaceSupportsErrorInfo(_ riid: COMInterfaceID) throws
}

public enum ISupportErrorInfoBinding: COMTwoWayBinding {
public typealias SwiftObject = ISupportErrorInfo
public typealias ABIStruct = COM_ABI.SWRT_ISupportErrorInfo

public static var interfaceID: COMInterfaceID { uuidof(ABIStruct.self) }
public static var virtualTablePointer: UnsafeRawPointer { .init(withUnsafePointer(to: &virtualTable) { $0 }) }

public static func _wrap(_ reference: consuming ABIReference) -> SwiftObject {
Import(_wrapping: reference)
}

public static func toCOM(_ object: SwiftObject) throws -> ABIReference {
try Import.toCOM(object)
}

private final class Import: COMImport<ISupportErrorInfoBinding>, ISupportErrorInfoProtocol {
public func interfaceSupportsErrorInfo(_ riid: COMInterfaceID) throws { try _interop.interfaceSupportsErrorInfo(riid) }
}

private static var virtualTable: COM_ABI.SWRT_ISupportErrorInfo_VirtualTable = .init(
QueryInterface: { IUnknownVirtualTable.QueryInterface($0, $1, $2) },
AddRef: { IUnknownVirtualTable.AddRef($0) },
Release: { IUnknownVirtualTable.Release($0) },
InterfaceSupportsErrorInfo: { this, riid in _implement(this) {
guard let riid else { throw COMError.invalidArg }
let riid_swift = GUIDBinding.fromABI(riid.pointee)
try $0.interfaceSupportsErrorInfo(riid_swift)
} })
}

public func uuidof(_: COM_ABI.SWRT_ISupportErrorInfo.Type) -> COMInterfaceID {
.init(0xDF0B3D60, 0x548F, 0x101B, 0x8E65, 0x08002B2BD119)
}

extension COMInterop where ABIStruct == COM_ABI.SWRT_ISupportErrorInfo {
public func interfaceSupportsErrorInfo(_ riid: COMInterfaceID) throws {
var riid_abi = GUIDBinding.toABI(riid)
try COMError.fromABI(this.pointee.VirtualTable.pointee.InterfaceSupportsErrorInfo(this, &riid_abi))
}
}
6 changes: 6 additions & 0 deletions Support/Sources/COM/SupportErrorInfoForAllInterfaces.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// An implementation of ISupportErrorInfo which reports that all interfaces support error info.
public final class SupportErrorInfoForAllInterfaces: COMTearOffBase<ISupportErrorInfoBinding>, ISupportErrorInfoProtocol {
public func interfaceSupportsErrorInfo(_ riid: COMInterfaceID) throws {
// Never throw. By virtue of projection, all interfaces report their errors through IErrorInfo.
}
}
11 changes: 11 additions & 0 deletions Support/Sources/COM_ABI/include/SWRT/winapi/oaidl.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,14 @@ struct SWRT_IErrorInfo_VirtualTable {
SWRT_HResult (__stdcall *GetHelpFile)(SWRT_IErrorInfo* _this, SWRT_BStr* helpFile);
SWRT_HResult (__stdcall *GetHelpContext)(SWRT_IErrorInfo* _this, uint32_t* helpContext);
};

typedef struct SWRT_ISupportErrorInfo {
struct SWRT_ISupportErrorInfo_VirtualTable* VirtualTable;
} SWRT_ISupportErrorInfo;

struct SWRT_ISupportErrorInfo_VirtualTable {
SWRT_HResult (__stdcall *QueryInterface)(SWRT_ISupportErrorInfo* _this, SWRT_Guid* riid, void** ppvObject);
uint32_t (__stdcall *AddRef)(SWRT_ISupportErrorInfo* _this);
uint32_t (__stdcall *Release)(SWRT_ISupportErrorInfo* _this);
SWRT_HResult (__stdcall *InterfaceSupportsErrorInfo)(SWRT_ISupportErrorInfo* _this, SWRT_Guid* riid);
};
2 changes: 1 addition & 1 deletion Support/Sources/WindowsRuntime/ComposableClass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ open class ComposableClass: IInspectableProtocol {

// Check for additional implemented interfaces.
if let interfaceBinding = type(of: owner).queriableInterfaces.first(where: { $0.interfaceID == id }) {
return COMDelegatingTearOff(virtualTable: interfaceBinding.virtualTablePointer, owner: owner).toCOM()
return COMDelegatingTearOff(owner: owner, virtualTable: interfaceBinding.virtualTablePointer).toCOM()
}

return try owner._queryInnerInterface(id)
Expand Down
2 changes: 2 additions & 0 deletions Support/Sources/WindowsRuntime/ExportedDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public final class ExportedDelegate<Binding: DelegateBinding>: COMEmbedderEx, IU
return toCOM().cast()
case FreeThreadedMarshalBinding.interfaceID:
return try FreeThreadedMarshal(self).toCOM().cast()
case ISupportErrorInfoBinding.interfaceID:
return SupportErrorInfoForAllInterfaces(owner: self).toCOM().cast()
default:
throw COMError.noInterface
}
Expand Down
4 changes: 3 additions & 1 deletion Support/Sources/WindowsRuntime/WinRTExportBase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import COM
open class WinRTExportBase<PrimaryInterfaceBinding: InterfaceBinding>: COMExportBase<PrimaryInterfaceBinding>, IInspectableProtocol {
open class var _runtimeClassName: String { String(describing: Self.self) }
open class var _trustLevel: TrustLevel { .base }
open class var implementIStringable: Bool { true }
open class var implementIWeakReferenceSource: Bool { true }
open class var implementIStringable: Bool { true }

open override func _queryInterface(_ id: COMInterfaceID) throws -> IUnknownReference {
switch id {
Expand All @@ -27,6 +27,8 @@ open class WinRTExportBase<PrimaryInterfaceBinding: InterfaceBinding>: COMExport
open func getIids() throws -> [COMInterfaceID] {
var iids = Self.queriableInterfaces.map { $0.interfaceID }
if Self.implementIAgileObject { iids.append(IAgileObjectBinding.interfaceID) }
if Self.implementFreeThreadedMarshaling { iids.append(FreeThreadedMarshalBinding.interfaceID) }
if Self.implementISupportErrorInfo { iids.append(ISupportErrorInfoBinding.interfaceID) }
if Self.implementIWeakReferenceSource { iids.append(IWeakReferenceSourceBinding.interfaceID) }
if Self.implementIStringable, self is CustomStringConvertible { iids.append(WindowsFoundation_IStringableBinding.interfaceID) }
return iids
Expand Down

0 comments on commit 0c93b3e

Please sign in to comment.