Skip to content

Commit

Permalink
Cleanup COMIInspectableStruct and add HString.
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanlabelle committed Mar 9, 2024
1 parent f8d2ca2 commit 9e7e28a
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 88 deletions.
33 changes: 0 additions & 33 deletions Support/Sources/WindowsRuntime/COMInterop+IInspectable.swift

This file was deleted.

52 changes: 0 additions & 52 deletions Support/Sources/WindowsRuntime/HSTRING+methods.swift

This file was deleted.

68 changes: 68 additions & 0 deletions Support/Sources/WindowsRuntime/HString.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import WindowsRuntime_ABI
import COM

/// Wraps a Windows Runtime HSTRING.
public struct HString: ~Copyable {
public static var empty: HString { HString(transferring: nil) }

public let abi: WindowsRuntime_ABI.SWRT_HString?

public init(transferring abi: WindowsRuntime_ABI.SWRT_HString?) {
self.abi = abi
}

public init(duplicating abi: WindowsRuntime_ABI.SWRT_HString?) throws {
var duplicated: WindowsRuntime_ABI.SWRT_HString?
try HResult.throwIfFailed(WindowsRuntime_ABI.SWRT_WindowsDuplicateString(abi, &duplicated))
self.init(transferring: duplicated)
}

deinit { Self.delete(abi) }

public static func create(_ value: String) throws -> HString {
if value.isEmpty { return .empty }

// Preallocate and fill a UTF-16 HSTRING_BUFFER
var buffer: WindowsRuntime_ABI.SWRT_HStringBuffer? = nil
var pointer: UnsafeMutablePointer<UInt16>? = 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 }
_ = 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)) }
catch {
WindowsRuntime_ABI.SWRT_WindowsDeleteStringBuffer(buffer)
throw error
}

return .init(transferring: abi)
}

public static func toString(_ abi: WindowsRuntime_ABI.SWRT_HString?) -> String {
var length: UInt32 = 0
guard let ptr = WindowsRuntime_ABI.SWRT_WindowsGetStringRawBuffer(abi, &length) else { return "" }
let buffer: UnsafeBufferPointer<UTF16.CodeUnit> = .init(start: ptr, count: Int(length))
return String(decoding: buffer, as: UTF16.self)
}

public func toString() -> String { Self.toString(abi) }

public func duplicate() throws -> Self {
var duplicated: WindowsRuntime_ABI.SWRT_HString?
try HResult.throwIfFailed(WindowsRuntime_ABI.SWRT_WindowsDuplicateString(abi, &duplicated))
return .init(transferring: duplicated)
}

public static func delete(_ abi: WindowsRuntime_ABI.SWRT_HString?) {
let hr = WindowsRuntime_ABI.SWRT_WindowsDeleteString(abi)
assert(HResult.isSuccess(hr), "Failed to delete HSTRING")
}

public consuming func detach() -> WindowsRuntime_ABI.SWRT_HString? {
let abi = self.abi
discard self
return abi
}
}
6 changes: 3 additions & 3 deletions Support/Sources/WindowsRuntime/HStringProjection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ public enum HStringProjection: ABIProjection {
public static var abiDefaultValue: ABIValue { nil }

public static func toSwift(_ value: WindowsRuntime_ABI.SWRT_HString?) -> SwiftValue {
value.toString()
HString.toString(value)
}

public static func toABI(_ value: String) throws -> WindowsRuntime_ABI.SWRT_HString? {
try WindowsRuntime_ABI.SWRT_HString.create(value)
try HString.create(value).detach()
}

public static func release(_ value: inout WindowsRuntime_ABI.SWRT_HString?) {
WindowsRuntime_ABI.SWRT_HString.delete(value)
HString.delete(value)
value = nil
}
}
30 changes: 30 additions & 0 deletions Support/Sources/WindowsRuntime/IInspectable.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import COM
import WindowsRuntime_ABI
import struct Foundation.UUID

public protocol IInspectableProtocol: IUnknownProtocol {
func getIids() throws -> [COMInterfaceID]
Expand Down Expand Up @@ -36,10 +37,39 @@ public enum IInspectableProjection: WinRTTwoWayProjection {
GetTrustLevel: { WinRTExportedInterface.GetTrustLevel($0, $1) })
}

/// Identifies COM interface structs as deriving from IInspectable.
/// Do not use for dynamic casting because conformances will be @retroactive.
public protocol COMIInspectableStruct: COMIUnknownStruct {}

#if swift(>=5.10)
extension WindowsRuntime_ABI.SWRT_IInspectable: @retroactive COMIUnknownStruct {}
#endif

extension WindowsRuntime_ABI.SWRT_IInspectable: /* @retroactive */ COMIInspectableStruct {
public static let iid = COMInterfaceID(0xAF86E2E0, 0xB12D, 0x4C6A, 0x9C5A, 0xD7AA65101E90)
}

extension COMInterop where Interface: /* @retroactive */ COMIInspectableStruct {
private var inspectable: UnsafeMutablePointer<WindowsRuntime_ABI.SWRT_IInspectable>{
this.withMemoryRebound(to: WindowsRuntime_ABI.SWRT_IInspectable.self, capacity: 1) { $0 }
}

public func getIids() throws -> [Foundation.UUID] {
var iids: COMArray<WindowsRuntime_ABI.SWRT_Guid> = .null
try WinRTError.throwIfFailed(inspectable.pointee.lpVtbl.pointee.GetIids(inspectable, &iids.count, &iids.pointer))
defer { iids.deallocate() }
return WinRTArrayProjection<GUIDProjection>.toSwift(consuming: &iids)
}

public func getRuntimeClassName() throws -> String {
var runtimeClassName: WindowsRuntime_ABI.SWRT_HString?
try WinRTError.throwIfFailed(inspectable.pointee.lpVtbl.pointee.GetRuntimeClassName(inspectable, &runtimeClassName))
return HStringProjection.toSwift(consuming: &runtimeClassName)
}

public func getTrustLevel() throws -> TrustLevel {
var trustLevel: WindowsRuntime_ABI.SWRT_TrustLevel = 0
try WinRTError.throwIfFailed(inspectable.pointee.lpVtbl.pointee.GetTrustLevel(inspectable, &trustLevel))
return TrustLevel.toSwift(trustLevel)
}
}

0 comments on commit 9e7e28a

Please sign in to comment.