import CWinRT import Foundation // Protocols for WinRT types that are used by public APIs public protocol WinRTStruct {} public protocol WinRTEnum {} public protocol IWinRTObject: AnyObject { var thisPtr: WindowsFoundation.IInspectable { get } } public protocol WinRTInterface: AnyObject, CustomQueryInterface { } open class WinRTClass : CustomQueryInterface, Equatable { public init() {} @_spi(WinRTInternal) public init(_ ptr: WindowsFoundation.IInspectable) { _inner = ptr } @_spi(WinRTInternal) open func _getABI() -> UnsafeMutablePointer? { if T.self == C_IInspectable.self { return UnsafeMutableRawPointer(identity?.get())?.bindMemory(to: T.self, capacity: 1) ?? RawPointer(_inner) } if T.self == C_IUnknown.self { return UnsafeMutableRawPointer(identity?.get())?.bindMemory(to: T.self, capacity: 1) ?? RawPointer(_inner) } return nil } @_spi(WinRTInternal) public internal(set) var _inner: WindowsFoundation.IInspectable! var identity: ComPtr? @_spi(WinRTImplements) open func queryInterface(_ iid: WindowsFoundation.IID) -> IUnknownRef? { WindowsFoundation.queryInterface(self, iid) } deinit { // ensure we release the identity pointer before releasing _inner. releasing the _inner // cleans up the underlying COM object. identity = nil _inner = nil } } public func ==(_ lhs: T, _ rhs: T) -> Bool { return lhs.thisPtr == rhs.thisPtr } extension WinRTClass: IWinRTObject { public var thisPtr: WindowsFoundation.IInspectable { try! _inner.QueryInterface() } } @_spi(WinRTInternal) extension WinRTClass { public func copyTo(_ ptr: UnsafeMutablePointer?>?) { guard let ptr else { return } let result: UnsafeMutablePointer = _getABI()! result.withMemoryRebound(to: C_IInspectable.self, capacity: 1) { _ = $0.pointee.lpVtbl.pointee.AddRef($0) } ptr.initialize(to: result) } public func GetRuntimeClassName() -> HString { // always use the runtime class name of the inner WinRT object. the winui runtime will query for // class names and if it isn't recognized, it will call out to IXamlMetadataProvider (IXMP) // to get the associated XamlType. We aren't using Xaml for swift, so we don't actually // need or want the framework to think it's dealing with custom types. return try! _inner.GetRuntimeClassName() } fileprivate func aggregated() -> Bool { identity != nil } // Get an interface for caching on a class. This method properly handles // reference counting via releasing the reference added on the Swift object // in the case of being aggregated. The wrapper still has the +1 ref on it, // which will be released when the object is destroyed. We can safely let the // objects be destroyed since _inner is destroyed last. Releasing _inner is what // cleans up the underlying COM object. public func getInterfaceForCaching() -> T { let ptr:T = try! _inner.QueryInterface() if aggregated() { Unmanaged.passUnretained(self).release() } return ptr } }