Skip to content

Commit

Permalink
Expose ICreateErrorInfo + CreateErrorInfo and use it for creating IEr…
Browse files Browse the repository at this point in the history
…rorInfo objects (#258)
  • Loading branch information
tristanlabelle authored Sep 3, 2024
1 parent 571f96f commit 4c1f26e
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 15 deletions.
17 changes: 2 additions & 15 deletions Support/Sources/COM/COMError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public struct COMError: COMErrorProtocol, CustomStringConvertible {
}

public init(hresult: HResult, description: String?) {
self.init(hresult: hresult, errorInfo: description.map { DescriptiveErrorInfo(description: $0) })
self.init(hresult: hresult, errorInfo: description.flatMap { try? createErrorInfo(description: $0) })
}

public var description: String {
Expand Down Expand Up @@ -84,8 +84,7 @@ public struct COMError: COMErrorProtocol, CustomStringConvertible {

public static func toABI(hresult: HResult, description: String? = nil) -> HResult.Value {
guard hresult.isFailure else { return hresult.value }
try? Self.setErrorInfo(description.map { DescriptiveErrorInfo(description: $0) })
return hresult.value
return Self(hresult: hresult, description: description).toABI()
}

public static func getErrorInfo() throws -> IErrorInfo? {
Expand All @@ -100,16 +99,4 @@ public struct COMError: COMErrorProtocol, CustomStringConvertible {
defer { IErrorInfoProjection.release(&errorInfo) }
try fromABI(captureErrorInfo: false, COM_ABI.SWRT_SetErrorInfo(/* dwReserved: */ 0, errorInfo))
}

private final class DescriptiveErrorInfo: COMPrimaryExport<IErrorInfoProjection>, IErrorInfoProtocol {
private let _description: String
public init(description: String) { self._description = description }

// IErrorInfo
public var guid: GUID { get throws { throw COMError.fail } }
public var source: String? { get throws { throw COMError.fail } }
public var description: String? { self._description }
public var helpFile: String? { get throws { throw COMError.fail } }
public var helpContext: UInt32 { get throws { throw COMError.fail } }
}
}
80 changes: 80 additions & 0 deletions Support/Sources/COM/ICreateErrorInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import COM_ABI

public typealias ICreateErrorInfo = any ICreateErrorInfoProtocol
public protocol ICreateErrorInfoProtocol: IUnknownProtocol {
func setGUID(_ guid: GUID) throws
func setSource(_ source: String?) throws
func setDescription(_ description: String?) throws
func setHelpFile(_ helpFile: String?) throws
func setHelpContext(_ helpContext: UInt32) throws
}

public enum ICreateErrorInfoProjection: COMTwoWayProjection {
public typealias ABIStruct = COM_ABI.SWRT_ICreateErrorInfo
public typealias SwiftObject = ICreateErrorInfo

public static var interfaceID: COMInterfaceID { uuidof(ABIStruct.self) }
public static var virtualTablePointer: UnsafeRawPointer { .init(withUnsafePointer(to: &virtualTable) { $0 }) }

public static func _wrap(_ reference: consuming ABIReference) -> SwiftObject {
Import(_wrapping: reference)
}

public static func toCOM(_ object: SwiftObject) throws -> ABIReference {
try Import.toCOM(object)
}

private final class Import: COMImport<ICreateErrorInfoProjection>, ICreateErrorInfoProtocol {
public func setGUID(_ guid: GUID) throws { try _interop.setGUID(guid) }
public func setSource(_ source: String?) throws { try _interop.setSource(source) }
public func setDescription(_ description: String?) throws { try _interop.setDescription(description) }
public func setHelpFile(_ helpFile: String?) throws { try _interop.setHelpFile(helpFile) }
public func setHelpContext(_ helpContext: UInt32) throws { try _interop.setHelpContext(helpContext) }
}

private static var virtualTable: COM_ABI.SWRT_ICreateErrorInfo_VirtualTable = .init(
QueryInterface: { IUnknownVirtualTable.QueryInterface($0, $1, $2) },
AddRef: { IUnknownVirtualTable.AddRef($0) },
Release: { IUnknownVirtualTable.Release($0) },
SetGUID: { this, guid in _implement(this) {
guard let guid else { throw COMError.invalidArg }
try $0.setGUID(GUIDProjection.toSwift(guid.pointee))
} },
SetSource: { this, source in _implement(this) { try $0.setSource(BStrProjection.toSwift(source)) } },
SetDescription: { this, description in _implement(this) { try $0.setDescription(BStrProjection.toSwift(description)) } },
SetHelpFile: { this, helpFile in _implement(this) { try $0.setHelpFile(BStrProjection.toSwift(helpFile)) } },
SetHelpContext: { this, helpContext in _implement(this) { try $0.setHelpContext(helpContext) } })
}

public func uuidof(_: COM_ABI.SWRT_ICreateErrorInfo.Type) -> COMInterfaceID {
.init(0x22F03340, 0x547D, 0x101B, 0x8E65, 0x08002B2BD119)
}

extension COMInterop where ABIStruct == COM_ABI.SWRT_ICreateErrorInfo {
public func setGUID(_ guid: GUID) throws {
var guid = GUIDProjection.toABI(guid)
try COMError.fromABI(this.pointee.VirtualTable.pointee.SetGUID(this, &guid))
}

public func setSource(_ source: String?) throws {
var source = try BStrProjection.toABI(source)
defer { BStrProjection.release(&source) }
try COMError.fromABI(this.pointee.VirtualTable.pointee.SetSource(this, source))
}

public func setDescription(_ description: String?) throws {
var description = try BStrProjection.toABI(description)
defer { BStrProjection.release(&description) }
try COMError.fromABI(this.pointee.VirtualTable.pointee.SetDescription(this, description))
}

public func setHelpFile(_ helpFile: String?) throws {
var helpFile = try BStrProjection.toABI(helpFile)
defer { BStrProjection.release(&helpFile) }
try COMError.fromABI(this.pointee.VirtualTable.pointee.SetHelpFile(this, helpFile))
}

public func setHelpContext(_ helpContext: UInt32) throws {
try COMError.fromABI(this.pointee.VirtualTable.pointee.SetHelpContext(this, helpContext))
}
}
21 changes: 21 additions & 0 deletions Support/Sources/COM/createErrorInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import COM_ABI

/// Creates an instance of `ICreateErrorInfo`.
public func createErrorInfo() throws -> ICreateErrorInfo {
var createErrorInfo = ICreateErrorInfoProjection.abiDefaultValue
defer { ICreateErrorInfoProjection.release(&createErrorInfo) }
try COMError.fromABI(SWRT_CreateErrorInfo(&createErrorInfo))
return try NullResult.unwrap(ICreateErrorInfoProjection.toSwift(createErrorInfo))
}

/// Creates an instance of `IErrorInfo` with prepopulated fields.
public func createErrorInfo(guid: GUID? = nil, source: String? = nil, description: String?,
helpFile: String? = nil, helpContext: UInt32? = nil) throws -> IErrorInfo {
let errorInfo = try createErrorInfo()
if let guid { try errorInfo.setGUID(guid) }
if let source { try errorInfo.setSource(source) }
if let description { try errorInfo.setDescription(description) }
if let helpFile { try errorInfo.setHelpFile(helpFile) }
if let helpContext { try errorInfo.setHelpContext(helpContext) }
return try errorInfo.queryInterface(IErrorInfoProjection.self)
}
15 changes: 15 additions & 0 deletions Support/Sources/COM_ABI/include/SWRT/windows/oaidl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@
#include "SWRT/windows/wtypes.h"
#include "SWRT/windows/unknwn.h"

typedef struct SWRT_ICreateErrorInfo {
struct SWRT_ICreateErrorInfo_VirtualTable* VirtualTable;
} SWRT_ICreateErrorInfo;

struct SWRT_ICreateErrorInfo_VirtualTable {
SWRT_HResult (__stdcall *QueryInterface)(SWRT_ICreateErrorInfo* _this, SWRT_Guid* riid, void** ppvObject);
uint32_t (__stdcall *AddRef)(SWRT_ICreateErrorInfo* _this);
uint32_t (__stdcall *Release)(SWRT_ICreateErrorInfo* _this);
SWRT_HResult (__stdcall *SetGUID)(SWRT_ICreateErrorInfo* _this, SWRT_Guid* rguid);
SWRT_HResult (__stdcall *SetSource)(SWRT_ICreateErrorInfo* _this, SWRT_BStr source);
SWRT_HResult (__stdcall *SetDescription)(SWRT_ICreateErrorInfo* _this, SWRT_BStr description);
SWRT_HResult (__stdcall *SetHelpFile)(SWRT_ICreateErrorInfo* _this, SWRT_BStr helpFile);
SWRT_HResult (__stdcall *SetHelpContext)(SWRT_ICreateErrorInfo* _this, uint32_t helpContext);
};

typedef struct SWRT_IErrorInfo {
struct SWRT_IErrorInfo_VirtualTable* VirtualTable;
} SWRT_IErrorInfo;
Expand Down
1 change: 1 addition & 0 deletions Support/Sources/COM_ABI/include/SWRT/windows/oleauto.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "SWRT/windows/wtypes.h"
#include "SWRT/windows/oaidl.h"

SWRT_HResult SWRT_CreateErrorInfo(SWRT_ICreateErrorInfo ** pperrinfo);
SWRT_HResult SWRT_GetErrorInfo(uint32_t dwReserved, SWRT_IErrorInfo** pperrinfo);
SWRT_HResult SWRT_SetErrorInfo(uint32_t dwReserved, SWRT_IErrorInfo* perrinfo);
SWRT_BStr SWRT_SysAllocString(const char16_t* strIn);
Expand Down
4 changes: 4 additions & 0 deletions Support/Sources/COM_ABI/oleauto.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
#include <Windows.h>
#include <oleauto.h>

SWRT_HResult SWRT_CreateErrorInfo(SWRT_ICreateErrorInfo ** pperrinfo) {
return (SWRT_HResult)CreateErrorInfo((ICreateErrorInfo**)pperrinfo);
}

SWRT_HResult SWRT_GetErrorInfo(uint32_t dwReserved, SWRT_IErrorInfo** pperrinfo) {
return (SWRT_HResult)GetErrorInfo(dwReserved, (IErrorInfo**)pperrinfo);
}
Expand Down

0 comments on commit 4c1f26e

Please sign in to comment.