From 5d197bcbf3ac135a9f52596de512715ed8b68f50 Mon Sep 17 00:00:00 2001 From: Tristan Labelle Date: Tue, 5 Dec 2023 07:51:51 -0500 Subject: [PATCH] Finished IRestrictedErrorInfo vtable. Started generating vtables. --- ...emblyModuleFileWriter+referenceTypes.swift | 7 +- ...SwiftAssemblyModuleFileWriter+vtable.swift | 73 +++++++++++++++++++ .../WindowsRuntime/IRestrictedErrorInfo.swift | 17 ++++- 3 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 Generator/Sources/ProjectionGenerator/SwiftAssemblyModuleFileWriter+vtable.swift diff --git a/Generator/Sources/ProjectionGenerator/SwiftAssemblyModuleFileWriter+referenceTypes.swift b/Generator/Sources/ProjectionGenerator/SwiftAssemblyModuleFileWriter+referenceTypes.swift index 9e7b1e6f..f136a000 100644 --- a/Generator/Sources/ProjectionGenerator/SwiftAssemblyModuleFileWriter+referenceTypes.swift +++ b/Generator/Sources/ProjectionGenerator/SwiftAssemblyModuleFileWriter+referenceTypes.swift @@ -38,10 +38,9 @@ extension SwiftAssemblyModuleFileWriter { initialValue: try Self.toIIDExpression(WindowsMetadata.getInterfaceID(interfaceOrDelegate))) if classDefinition == nil { - writer.writeComputedProperty( - visibility: .public, static: true, name: "virtualTablePointer", - type: .identifier("COMVirtualTablePointer"), - get: { writer in writer.writeNotImplemented() }) + try writer.writeStoredProperty( + visibility: .public, static: true, declarator: .var, name: "virtualTablePointer", + initializer: { try writeVirtualTable(interfaceOrDelegate: interfaceOrDelegate, to: $0) }) } let isDelegate = interfaceOrDelegate.definition is DelegateDefinition diff --git a/Generator/Sources/ProjectionGenerator/SwiftAssemblyModuleFileWriter+vtable.swift b/Generator/Sources/ProjectionGenerator/SwiftAssemblyModuleFileWriter+vtable.swift new file mode 100644 index 00000000..257dae25 --- /dev/null +++ b/Generator/Sources/ProjectionGenerator/SwiftAssemblyModuleFileWriter+vtable.swift @@ -0,0 +1,73 @@ +import CodeWriters +import DotNetMetadata +import WindowsMetadata + +extension SwiftAssemblyModuleFileWriter { + func writeVirtualTable(interfaceOrDelegate: BoundType, to output: IndentedTextOutputStream) throws { + try output.writeIndentedBlock(header: "COMVirtualTable(", footer: ")") { + // IUnknown methods + output.writeFullLine("QueryInterface: { this, iid, ppvObject in _queryInterface(this, iid, ppvObject) },") + output.writeFullLine("AddRef: { this in _addRef(this) },") + output.write("Release: { this in _release(this) }") + + // IInspectable methods (except for delegates) + if interfaceOrDelegate.definition is InterfaceDefinition { + output.write(",", endLine: true) + output.writeFullLine("GetIids: { this, iidCount, iids in _getIids(this, iidCount, iids) },") + output.writeFullLine("GetRuntimeClassName: { this, className in _getRuntimeClassName(this, className) },") + output.write("GetTrustLevel: { this, trustLevel in _getTrustLevel(this, trustLevel) }") + } + + // Custom interface/delegate methods + for method in interfaceOrDelegate.definition.methods { + output.write(",", endLine: true) + try writeVirtualTableFunc(method, genericTypeArgs: interfaceOrDelegate.genericArgs, to: output) + } + } + } + + fileprivate func writeVirtualTableFunc(_ method: Method, genericTypeArgs: [TypeNode], to output: IndentedTextOutputStream) throws { + // Special case for getters + if try method.params.count == 0 && method.hasReturnValue { + return try writeVirtualTableGetter(method, genericTypeArgs: genericTypeArgs, to: output) + } + + try writeVirtualTableFuncImplementation( + name: method.findAttribute(OverloadAttribute.self) ?? method.name, + paramNames: method.params.map { $0.name! }, + to: output) { + // Declare Swift values for out params + // Invoke the Swift implementation + // Convert out params to the ABI representation + output.writeFullLine("fatalError(\"Not implemented: \\(#function)\")") + } + } + + fileprivate func writeVirtualTableGetter(_ method: Method, genericTypeArgs: [TypeNode], to output: IndentedTextOutputStream) throws { + let memberInvocation: String + if case .special = method.nameKind, method.name.hasPrefix("get_") { + let propertyName = method.name[method.name.index(method.name.startIndex, offsetBy: 4)...] + memberInvocation = Casing.pascalToCamel(String(propertyName)) + } else { + let methodName = projection.toMemberName(method) + memberInvocation = "\(methodName)()" + } + + let returnTypeProjection = try projection.getTypeProjection( + method.returnType.bindGenericParams(typeArgs: genericTypeArgs)) + let abiName = try method.findAttribute(OverloadAttribute.self) ?? method.name + output.write("\(abiName): { this, result in _getter(this, result) { " + + "try \(returnTypeProjection.projectionType).toABI($0.\(memberInvocation)) } },") + } + + fileprivate func writeVirtualTableFuncImplementation(name: String, paramNames: [String], to output: IndentedTextOutputStream, body: () throws -> Void) rethrows { + output.write(name) + output.write(": ") + output.write("{ this") + for paramName in paramNames { + output.write(", \(paramName)") + } + try output.writeIndentedBlock(header: " in _implement(this) { this in", body: body) + output.write("} }") + } +} \ No newline at end of file diff --git a/Support/Sources/WindowsRuntime/IRestrictedErrorInfo.swift b/Support/Sources/WindowsRuntime/IRestrictedErrorInfo.swift index 8bd46cf6..477e5942 100644 --- a/Support/Sources/WindowsRuntime/IRestrictedErrorInfo.swift +++ b/Support/Sources/WindowsRuntime/IRestrictedErrorInfo.swift @@ -54,7 +54,22 @@ public enum IRestrictedErrorInfoProjection: COMTwoWayProjection { QueryInterface: { this, iid, ppvObject in _queryInterface(this, iid, ppvObject) }, AddRef: { this in _addRef(this) }, Release: { this in _release(this) }, - GetErrorDetails: { this, _, _, _, _ in fatalError("Not implemented: \(#function)") }, + GetErrorDetails: { this, description, error, restrictedDescription, capabilitySid in _implement(this) { + var description_: String? = nil + var error_: HResult = .ok + var restrictedDescription_: String? = nil + var capabilitySid_: String? = nil + try $0.getErrorDetails(description: &description_, error: &error_, restrictedDescription: &restrictedDescription_, capabilitySid: &capabilitySid_) + var _success = false + if let description { description.pointee = try BStrProjection.toABI(description_) } + defer { if !_success, let description { BStrProjection.release(&description.pointee) } } + if let error { error.pointee = HResultProjection.toABI(error_) } + if let restrictedDescription { restrictedDescription.pointee = try BStrProjection.toABI(restrictedDescription_) } + defer { if !_success, let restrictedDescription { BStrProjection.release(&restrictedDescription.pointee) } } + if let capabilitySid { capabilitySid.pointee = try BStrProjection.toABI(capabilitySid_) } + defer { if !_success, let capabilitySid { BStrProjection.release(&capabilitySid.pointee) } } + _success = true + } }, GetReference: { this, reference in _getter(this, reference) { try BStrProjection.toABI($0.reference) } } ) }