Skip to content

Commit

Permalink
Added WinRTClassLoader with getActivationFactory (not used by generat…
Browse files Browse the repository at this point in the history
…ed code yet).
  • Loading branch information
tristanlabelle committed Mar 22, 2024
1 parent 70c84e8 commit fae49d7
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 4 deletions.
3 changes: 2 additions & 1 deletion Support/Sources/COM/COMReference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public struct COMReference<Interface>: ~Copyable /* where Interface: COMIUnknown
return pointer
}

public consuming func reinterpret<NewInterface: COMIUnknownStruct>(to type: NewInterface.Type = NewInterface.self) -> COMReference<NewInterface> {
// Should require COMIUnknownStruct but we run into compiler bugs.
public consuming func reinterpret<NewInterface>(to type: NewInterface.Type = NewInterface.self) -> COMReference<NewInterface> /* where Interface: COMIUnknownStruct */ {
let pointer = self.pointer
discard self
return COMReference<NewInterface>(transferringRef: pointer.withMemoryRebound(to: NewInterface.self, capacity: 1) { $0 })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ fileprivate var lazyPropertyValueStatics: COM.COMLazyReference<WindowsRuntime_AB
internal var propertyValueStatics: COMInterop<WindowsRuntime_ABI.SWRT_IPropertyValueStatics> {
get throws {
try lazyPropertyValueStatics.getInterop {
try getActivationFactory(
activatableId: "Windows.Foundation.PropertyValue",
id: WindowsRuntime_ABI.SWRT_IPropertyValueStatics.iid)
try WinRTClassLoader.default.getActivationFactory(
runtimeClass: "Windows.Foundation.PropertyValue",
interfaceID: WindowsRuntime_ABI.SWRT_IPropertyValueStatics.iid)
}
}
}
89 changes: 89 additions & 0 deletions Support/Sources/WindowsRuntime/WinRTClassLoader.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import WindowsRuntime_ABI
import WinSDK
import class Foundation.NSLock

/// Supports class instantiation for the WinRT projection.
open class WinRTClassLoader {
open func getActivationFactory<COMInterface>(runtimeClass: String, interfaceID: COMInterfaceID) throws -> COMReference<COMInterface> {
try getActivationFactory(runtimeClass: runtimeClass).reinterpret(to: COMInterface.self)
}

open func getActivationFactory(runtimeClass: String) throws -> COMReference<SWRT_IActivationFactory> {
try getActivationFactory(runtimeClass: runtimeClass, interfaceID: SWRT_IActivationFactory.iid)
}
}

extension WinRTClassLoader {
public static let `default`: WinRTClassLoader = Default()

private class Default: WinRTClassLoader {
override func getActivationFactory<COMInterface>(runtimeClass: String, interfaceID: COMInterfaceID) throws -> COMReference<COMInterface> {
var activatableId = try HStringProjection.toABI(runtimeClass)
defer { HStringProjection.release(&activatableId) }

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 }

let pointer = rawPointer.bindMemory(to: COMInterface.self, capacity: 1)
return COM.COMReference(transferringRef: pointer)
}
}
}

extension WinRTClassLoader {
public static func dll(name: String) -> WinRTClassLoader { Dll(name: name) }

private class Dll: WinRTClassLoader {
private let name: String
private let lock = NSLock()
private var libraryHandle: WinSDK.HMODULE?
private var cachedFuncPointer: WindowsRuntime_ABI.SWRT_DllGetActivationFactory?

init(name: String) {
self.name = name
}

deinit {
if let libraryHandle {
WinSDK.FreeLibrary(libraryHandle)
}
}

var funcPointer: WindowsRuntime_ABI.SWRT_DllGetActivationFactory {
get throws {
if let cachedFuncPointer { return cachedFuncPointer }

lock.lock()
defer { lock.unlock() }

if libraryHandle == nil {
name.withCString(encodedAs: UTF16.self) { name in
libraryHandle = WinSDK.LoadLibraryW(name)
}
guard libraryHandle != nil else { throw HResult.Error.fail }
}

guard let rawFuncPointer = WinSDK.GetProcAddress(libraryHandle, "DllGetActivationFactory") else {
throw HResult.Error.fail
}

let funcPointer = unsafeBitCast(rawFuncPointer, to: WindowsRuntime_ABI.SWRT_DllGetActivationFactory.self)
self.cachedFuncPointer = funcPointer
return funcPointer
}
}

override func getActivationFactory(runtimeClass: String) throws -> COMReference<SWRT_IActivationFactory> {
var activatableId = try HStringProjection.toABI(runtimeClass)
defer { HStringProjection.release(&activatableId) }

var factoryPointer: UnsafeMutablePointer<SWRT_IActivationFactory>?
try WinRTError.throwIfFailed(funcPointer(activatableId, &factoryPointer))
guard let factoryPointer else { throw HResult.Error.noInterface }

return COM.COMReference(transferringRef: factoryPointer)
}
}
}
7 changes: 7 additions & 0 deletions Support/Sources/WindowsRuntime_ABI/include/SWRT/winrt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include "SWRT/BaseTsd.h"
#include "SWRT/winstring.h"
#include "SWRT/activation.h"

typedef SWRT_HResult(__stdcall *SWRT_DllGetActivationFactory)(SWRT_HString activatableClassId, SWRT_IActivationFactory** factory);

0 comments on commit fae49d7

Please sign in to comment.