2024-02-15 17:18:14 -08:00

79 lines
2.7 KiB
Swift

import CWinRT
import CWinAppSDK
import WindowsFoundation
import WinSDK
public enum ThreadingModel {
case single
case multi
}
/// WindowsAppRuntimeInitializer is used to properly initialize the Windows App SDK runtime, along with the Windows Runtime.
/// The runtime is initalized for the lifetime of the object, and is deinitialized when the object is deallocated.
/// Example usage:
/// ```
/// public static func main() {
/// do {
/// try withExtendedLifetime(WindowsAppRuntimeInitializer()) {
/// initialization code here
/// }
/// }
/// catch {
/// fatalError("Failed to initialize WindowsAppRuntimeInitializer: \(error)")
/// }
/// }
/// ```
public class WindowsAppRuntimeInitializer {
// TODO: Figure out how to properly link against delayimp.lib so that we can delay load the bootstrap dll.
private typealias pfnMddBootstrapInitialize2 = @convention(c) (UInt32, PCWSTR?, PACKAGE_VERSION, MddBootstrapInitializeOptions) -> HRESULT
private typealias pfnMddBootstrapShutdown = @convention(c) () -> Void
private let bootsrapperDll = LoadLibraryA("swift-windowsappsdk_CWinAppSDK.resources\\Microsoft.WindowsAppRuntime.Bootstrap.dll")
private lazy var Initialize: pfnMddBootstrapInitialize2 = {
let pfn = GetProcAddress(bootsrapperDll, "MddBootstrapInitialize2")
return unsafeBitCast(pfn, to: pfnMddBootstrapInitialize2.self)
}()
private lazy var Shutdown: pfnMddBootstrapShutdown = {
let pfn = GetProcAddress(bootsrapperDll, "MddBootstrapShutdown")
return unsafeBitCast(pfn, to: pfnMddBootstrapShutdown.self)
}()
private func processHasIdentity() -> Bool {
var length: UInt32 = 0
return GetCurrentPackageFullName(&length, nil) != APPMODEL_ERROR_NO_PACKAGE
}
public init(threadingModel: ThreadingModel = .single) throws {
let roInitParam = switch threadingModel {
case .single: RO_INIT_SINGLETHREADED
case .multi: RO_INIT_MULTITHREADED
}
try CHECKED(RoInitialize(roInitParam))
try CHECKED(SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE))
guard !processHasIdentity() else {
return
}
try CHECKED(Initialize(
UInt32(WINDOWSAPPSDK_RELEASE_MAJORMINOR),
WINDOWSAPPSDK_RELEASE_VERSION_TAG_SWIFT,
.init(),
MddBootstrapInitializeOptions(
MddBootstrapInitializeOptions_OnNoMatch_ShowUI.rawValue
)
))
}
deinit {
RoUninitialize()
if !processHasIdentity() {
Shutdown()
}
FreeLibrary(bootsrapperDll)
}
}