Skip to content

Commit

Permalink
More tweaks to COMExportedInterface
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanlabelle committed Jan 12, 2024
1 parent 12d0709 commit 3a921d6
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 85 deletions.
17 changes: 7 additions & 10 deletions Support/Sources/COM/COMExport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ open class COMExportBase: IUnknownProtocol {
open class var implements: [Implements] { [] }

fileprivate var comInterface: COMExportedInterface
public var unknownPointer: IUnknownPointer { comInterface.pointer }
public var unknownPointer: IUnknownPointer { comInterface.unknownPointer }
open var anyImplementation: Any { self }

fileprivate init(later: Void) { comInterface = .null }
fileprivate init(later: Void) { comInterface = .uninitialized }

open func _queryInterfacePointer(_ id: COMInterfaceID) throws -> IUnknownPointer {
if id == IUnknownProjection.id { return unknownPointer.addingRef() }
Expand All @@ -52,28 +52,25 @@ open class COMExportBase: IUnknownProtocol {
}

public static func getImplementationUnsafe<Projection: COMProjection>(_ this: Projection.COMPointer, projection: Projection.Type) -> Projection.SwiftObject {
getImplementation(unwrapped: COMExportedInterface.unwrapObjectUnsafe(IUnknownPointer.cast(this)), projection: Projection.self)!
getImplementation(unwrapped: COMExportedInterface.unwrapUnsafe(this), projection: Projection.self)!
}

public static func getImplementation<Projection: COMProjection>(_ this: Projection.COMPointer, projection: Projection.Type) -> Projection.SwiftObject? {
guard COMExportedInterface.test(IUnknownPointer.cast(this)) else { return nil }
return getImplementation(unwrapped: COMExportedInterface.unwrapObjectUnsafe(IUnknownPointer.cast(this)), projection: Projection.self)
guard COMExportedInterface.test(this) else { return nil }
return getImplementation(unwrapped: COMExportedInterface.unwrapUnsafe(this), projection: Projection.self)
}
}

/// Base for classes exported to COM.
open class COMExport<Projection: COMTwoWayProjection>: COMExportBase {
open var implementation: Projection.SwiftObject { self as! Projection.SwiftObject }
public var comPointer: Projection.COMPointer {
comInterface.pointer.withMemoryRebound(to: Projection.COMInterface.self, capacity: 1) { $0 }
comInterface.unknownPointer.cast(to: Projection.COMInterface.self)
}

public init() {
super.init(later: ())
comInterface = .init(
swiftObject: self,
virtualTable: Projection.virtualTablePointer.withMemoryRebound(
to: IUnknownProjection.COMVirtualTable.self, capacity: 1) { $0 })
comInterface = .init(swiftObject: self, virtualTable: Projection.virtualTablePointer)
}

open override func _queryInterfacePointer(_ id: COMInterfaceID) throws -> IUnknownPointer {
Expand Down
34 changes: 16 additions & 18 deletions Support/Sources/COM/COMExportedInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,48 @@ import CWinRTCore
/// Lays out a COM interface for exporting to COM consumers.
public struct COMExportedInterface {
private static let markerInterfaceId: COMInterfaceID = .init(0x33934271, 0x7009, 0x4EF3, 0x90F1, 0x02090D7EBD64)
public static var null: COMExportedInterface { .init() }
public static var uninitialized: COMExportedInterface { .init() }

private var comObject: CWinRTCore.SWRT_SwiftCOMObject

private init() {
comObject = .init()
}

public init<SwiftObject: IUnknownProtocol>(swiftObject: SwiftObject, virtualTable: IUnknownProjection.COMVirtualTablePointer) {
public init<SwiftObject: IUnknownProtocol, VirtualTable>(
swiftObject: SwiftObject,
virtualTable: UnsafePointer<VirtualTable>) {
comObject = .init(
comVirtualTable: virtualTable,
comVirtualTable: virtualTable.withMemoryRebound(to: CWinRTCore.SWRT_IUnknownVTable.self, capacity: 1) { $0 },
swiftObject: Unmanaged<AnyObject>.passUnretained(swiftObject).toOpaque())
}

public var pointer: IUnknownPointer {
public var isInitialized: Bool { comObject.swiftObject != nil }

public var unknownPointer: IUnknownPointer {
mutating get {
withUnsafeMutablePointer(to: &comObject) {
IUnknownPointer.cast($0)
}
}
}

fileprivate static func toUnmanagedUnsafe(_ this: IUnknownPointer) -> Unmanaged<AnyObject> {
fileprivate static func toUnmanagedUnsafe<Interface>(_ this: UnsafeMutablePointer<Interface>) -> Unmanaged<AnyObject> {
this.withMemoryRebound(to: CWinRTCore.SWRT_SwiftCOMObject.self, capacity: 1) {
Unmanaged<AnyObject>.fromOpaque($0.pointee.swiftObject)
}
}

public static func test(_ this: IUnknownPointer) -> Bool {
do { try this.queryInterface(markerInterfaceId).release() } catch { return false }
public static func test<Interface>(_ this: UnsafeMutablePointer<Interface>) -> Bool {
do { try IUnknownPointer.cast(this).queryInterface(markerInterfaceId).release() } catch { return false }
return true
}

public static func unwrapObjectUnsafe(_ this: IUnknownPointer) -> AnyObject {
public static func unwrapUnsafe<Interface>(_ this: UnsafeMutablePointer<Interface>) -> AnyObject {
toUnmanagedUnsafe(this).takeUnretainedValue()
}

public static func unwrapObject(_ this: IUnknownPointer) -> AnyObject? {
test(this) ? unwrapUnsafe(this) : nil
}

public static func unwrapUnsafe(_ this: IUnknownPointer) -> IUnknown {
unwrapObjectUnsafe(this) as! IUnknown
}

public static func unwrap(_ this: IUnknownPointer) -> IUnknown? {
public static func unwrap<Interface>(_ this: UnsafeMutablePointer<Interface>) -> AnyObject? {
test(this) ? unwrapUnsafe(this) : nil
}
}
Expand Down Expand Up @@ -97,7 +93,9 @@ extension COMExportedInterface {
return HResult.catchValue {
let id = GUIDProjection.toSwift(iid.pointee)
let this = IUnknownPointer.cast(this)
let unknownWithRef = id == markerInterfaceId ? this.addingRef() : try unwrapUnsafe(this)._queryInterfacePointer(id)
let unknownWithRef = id == markerInterfaceId
? this.addingRef()
: try (unwrapUnsafe(this) as! IUnknown)._queryInterfacePointer(id)
ppvObject.pointee = UnsafeMutableRawPointer(unknownWithRef)
}
}
Expand Down
16 changes: 15 additions & 1 deletion Support/Sources/COM/COMInterfaceID.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import struct Foundation.UUID
public typealias COMInterfaceID = Foundation.UUID

extension COMInterfaceID {
// Initializer supporting a GUID-like syntax: .init(0x00000000, 0x0000, 0x0000, 0xC000, 0x000000000046)
/// Initializer supporting a GUID-like syntax: .init(0x00000000, 0x0000, 0x0000, 0xC000, 0x000000000046)
public init(_ data1: UInt32, _ data2: UInt16, _ data3: UInt16, _ data4: UInt16, _ data5: UInt64) {
precondition(data5 < 0x1_00_00_00_00_00_00)
let bytes = (
Expand All @@ -16,4 +16,18 @@ extension COMInterfaceID {
UInt8((data5 >> 8) & 0xFF), UInt8((data5 >> 0) & 0xFF))
self.init(uuid: bytes)
}

/// Initializer for copying out of ILSpy
/// [Windows.Foundation.Metadata.Guid(2908547984u, 62745, 22786, 149, 48, 215, 242, 47, 226, 221, 132)]
public init(
_ data1: UInt32, _ data2: UInt16, _ data3: UInt16,
_ data4: UInt8, _ data5: UInt8, _ data6: UInt8, _ data7: UInt8,
_ data8: UInt8, _ data9: UInt8, _ data10: UInt8, _ data11: UInt8) {
let bytes = (
UInt8((data1 >> 24) & 0xFF), UInt8((data1 >> 16) & 0xFF), UInt8((data1 >> 8) & 0xFF), UInt8((data1 >> 0) & 0xFF),
UInt8((data2 >> 8) & 0xFF), UInt8((data2 >> 0) & 0xFF),
UInt8((data3 >> 8) & 0xFF), UInt8((data3 >> 0) & 0xFF),
data4, data5, data6, data7, data8, data9, data10, data11)
self.init(uuid: bytes)
}
}
60 changes: 4 additions & 56 deletions Support/Sources/WindowsRuntime/WinRTExportedInterface.swift
Original file line number Diff line number Diff line change
@@ -1,68 +1,16 @@
import COM
import CWinRTCore

/// Lays out a WinRT interface for exporting to WinRT consumers.
public struct WinRTExportedInterface {
public static var null: WinRTExportedInterface { .init() }

private var com: COMExportedInterface

private init() {
com = .null
}

public init<SwiftObject: IInspectableProtocol>(swiftObject: SwiftObject, virtualTable: IInspectableProjection.COMVirtualTablePointer) {
com = .init(
swiftObject: swiftObject,
virtualTable: virtualTable.withMemoryRebound(to: IUnknownProjection.COMVirtualTable.self, capacity: 1) { $0 })
}

public var unknownPointer: IUnknownPointer {
mutating get {
com.pointer
}
}

public var inspectablePointer: IInspectablePointer {
mutating get {
IInspectablePointer.cast(com.pointer)
}
}

public static func unwrapUnsafe(_ this: IInspectablePointer) -> IInspectable {
COMExportedInterface.unwrapObjectUnsafe(IUnknownPointer.cast(this)) as! IInspectable
}

public static func unwrap(_ this: IInspectablePointer) -> IInspectable? {
COMExportedInterface.test(IUnknownPointer.cast(this)) ? unwrapUnsafe(this) : nil
}
}

/// IInspectable virtual table implementations
extension WinRTExportedInterface {
public static func AddRef<Interface>(_ this: UnsafeMutablePointer<Interface>?) -> UInt32 {
COMExportedInterface.AddRef(this)
}

public static func Release<Interface>(_ this: UnsafeMutablePointer<Interface>?) -> UInt32 {
COMExportedInterface.Release(this)
}

public static func QueryInterface<Interface>(
_ this: UnsafeMutablePointer<Interface>?,
_ iid: UnsafePointer<CWinRTCore.SWRT_Guid>?,
_ ppvObject: UnsafeMutablePointer<UnsafeMutableRawPointer?>?) -> CWinRTCore.SWRT_HResult {
COMExportedInterface.QueryInterface(this, iid, ppvObject)
}

public enum WinRTExportedInterface {
public static func GetIids<Interface>(
_ this: UnsafeMutablePointer<Interface>?,
_ count: UnsafeMutablePointer<UInt32>?,
_ iids: UnsafeMutablePointer<UnsafeMutablePointer<CWinRTCore.SWRT_Guid>?>?) -> CWinRTCore.SWRT_HResult {
guard let this, let count, let iids else { return HResult.invalidArg.value }
count.pointee = 0
iids.pointee = nil
let object = unwrapUnsafe(IInspectablePointer.cast(this))
let object = COMExportedInterface.unwrapUnsafe(this) as! IInspectable
return HResult.catchValue {
let idsArray = try object.getIids()
let comArray = try WinRTArrayProjection<GUIDProjection>.toABI(idsArray)
Expand All @@ -76,7 +24,7 @@ extension WinRTExportedInterface {
_ className: UnsafeMutablePointer<CWinRTCore.SWRT_HString?>?) -> CWinRTCore.SWRT_HResult {
guard let this, let className else { return HResult.invalidArg.value }
className.pointee = nil
let object = unwrapUnsafe(IInspectablePointer.cast(this))
let object = COMExportedInterface.unwrapUnsafe(this) as! IInspectable
return HResult.catchValue {
className.pointee = try HStringProjection.toABI(object.getRuntimeClassName())
}
Expand All @@ -86,7 +34,7 @@ extension WinRTExportedInterface {
_ this: UnsafeMutablePointer<Interface>?,
_ trustLevel: UnsafeMutablePointer<CWinRTCore.SWRT_TrustLevel>?) -> CWinRTCore.SWRT_HResult {
guard let this, let trustLevel else { return HResult.invalidArg.value }
let object = unwrapUnsafe(IInspectablePointer.cast(this))
let object = COMExportedInterface.unwrapUnsafe(this) as! IInspectable
return HResult.catchValue {
trustLevel.pointee = try TrustLevel.toABI(object.getTrustLevel())
}
Expand Down

0 comments on commit 3a921d6

Please sign in to comment.