Skip to content

Commit

Permalink
cache factories and use fast pass strings (#142)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenbrix authored Mar 1, 2024
1 parent f5c3a60 commit 499c448
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 56 deletions.
57 changes: 57 additions & 0 deletions swiftwinrt/Resources/CWinRT/CppInteropWorkaround.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ typedef GUID_Workaround UUID_Workaround;
// Functions depending on workaround types
typedef struct IUnknown_Workaround IUnknown_Workaround;
typedef struct IInspectable_Workaround IInspectable_Workaround;
typedef struct IActivationFactory_Workaround IActivationFactory_Workaround;
typedef struct IMarshal_Workaround IMarshal_Workaround;

#include <combaseapi.h>
Expand Down Expand Up @@ -66,6 +67,12 @@ inline HRESULT RoGetActivationFactory_Workaround(
#endif
}

// Since we can't define statically allocated arrays in swift, just use a large enough buffer to hold the data.
// In reality this could probably be closer to 128
struct StaticWCharArray_512 {
WCHAR Data[512];
};

//-------------------------------------------------------------------------------------------------
// Begin the great lie
// Everything below will unknowingly use Xxx_Workaround.
Expand All @@ -91,6 +98,8 @@ inline HRESULT RoGetActivationFactory_Workaround(
#define IInspectableVtbl IInspectableVtbl_Workaround
#define IMarshal IMarshal_Workaround
#define IMarshalVtbl IMarshalVtbl_Workaround
#define IActivationFactory IActivationFactory_Workaround
#define IActivationFactoryVtbl IActivationFactoryVtbl_Workaround

// iunknown.h
typedef struct IUnknownVtbl
Expand Down Expand Up @@ -234,4 +243,52 @@ typedef struct IMarshalVtbl
interface IMarshal
{
CONST_VTBL struct IMarshalVtbl *lpVtbl;
};

typedef struct IActivationFactoryVtbl
{
BEGIN_INTERFACE

DECLSPEC_XFGVIRT(IUnknown, QueryInterface)
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
__RPC__in IActivationFactory * This,
/* [in] */ __RPC__in REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);

DECLSPEC_XFGVIRT(IUnknown, AddRef)
ULONG ( STDMETHODCALLTYPE *AddRef )(
__RPC__in IActivationFactory * This);

DECLSPEC_XFGVIRT(IUnknown, Release)
ULONG ( STDMETHODCALLTYPE *Release )(
__RPC__in IActivationFactory * This);

DECLSPEC_XFGVIRT(IInspectable, GetIids)
HRESULT ( STDMETHODCALLTYPE *GetIids )(
__RPC__in IActivationFactory * This,
/* [out] */ __RPC__out ULONG *iidCount,
/* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*iidCount) IID **iids);

DECLSPEC_XFGVIRT(IInspectable, GetRuntimeClassName)
HRESULT ( STDMETHODCALLTYPE *GetRuntimeClassName )(
__RPC__in IActivationFactory * This,
/* [out] */ __RPC__deref_out_opt HSTRING *className);

DECLSPEC_XFGVIRT(IInspectable, GetTrustLevel)
HRESULT ( STDMETHODCALLTYPE *GetTrustLevel )(
__RPC__in IActivationFactory * This,
/* [out] */ __RPC__out TrustLevel *trustLevel);

DECLSPEC_XFGVIRT(IActivationFactory, ActivateInstance)
HRESULT ( STDMETHODCALLTYPE *ActivateInstance )(
__RPC__in IActivationFactory * This,
/* [out] */ __RPC__deref_out_opt IInspectable **instance);

END_INTERFACE
} IActivationFactoryVtbl;

interface IActivationFactory
{
CONST_VTBL struct IActivationFactoryVtbl *lpVtbl;
};
4 changes: 4 additions & 0 deletions swiftwinrt/Resources/Support/CppInteropWorkaround.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public typealias C_IInspectable = C_BINDINGS_MODULE.IInspectable_Workaround
public typealias C_IInspectableVtbl = C_BINDINGS_MODULE.IInspectableVtbl_Workaround
public typealias C_IMarshal = C_BINDINGS_MODULE.IMarshal_Workaround
public typealias C_IMarshalVtbl = C_BINDINGS_MODULE.IMarshalVtbl_Workaround
public typealias C_IActivationFactory = C_BINDINGS_MODULE.IActivationFactory_Workaround
public typealias C_IActivationFactoryVtbl = C_BINDINGS_MODULE.IActivationFactoryVtbl_Workaround
internal let CoCreateInstance = C_BINDINGS_MODULE.CoCreateInstance_Workaround
internal let UuidFromStringA = C_BINDINGS_MODULE.UuidFromStringA_Workaround
internal let RoActivateInstance = C_BINDINGS_MODULE.RoActivateInstance_Workaround
Expand All @@ -26,6 +28,8 @@ public typealias C_IInspectable = C_BINDINGS_MODULE.IInspectable
public typealias C_IInspectableVtbl = C_BINDINGS_MODULE.IInspectableVtbl
public typealias C_IMarshal = C_BINDINGS_MODULE.IMarshal
public typealias C_IMarshalVtbl = C_BINDINGS_MODULE.IMarshalVtbl
public typealias C_IActivationFactory = C_BINDINGS_MODULE.IActivationFactory
public typealias C_IActivationFactoryVtbl = C_BINDINGS_MODULE.IActivationFactoryVtbl
internal let CoCreateInstance = C_BINDINGS_MODULE.CoCreateInstance
internal let UuidFromStringA = C_BINDINGS_MODULE.UuidFromStringA
internal let RoActivateInstance = C_BINDINGS_MODULE.RoActivateInstance
Expand Down
2 changes: 1 addition & 1 deletion swiftwinrt/Resources/Support/PropertyValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import WinSDK
// Handwritten implementation for PropertyValue which *doesn't* try to do the IInspectable <-> Any mapping.
// This class is used by the AnyWrapper to create IInspectable instances from this subset of known Any values.
internal final class PropertyValue {
private static let _IPropertyValueStatics: IPropertyValueStatics = try! RoGetActivationFactory(HString("Windows.Foundation.PropertyValue"))
private static let _IPropertyValueStatics: IPropertyValueStatics = try! RoGetActivationFactory("Windows.Foundation.PropertyValue")

public static func createUInt8(_ value: UInt8) -> SUPPORT_MODULE.IInspectable {
let propertyValue = try! _IPropertyValueStatics.CreateUInt8Impl(value)
Expand Down
29 changes: 21 additions & 8 deletions swiftwinrt/Resources/Support/Runtime+Swift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,33 @@
import WinSDK
import C_BINDINGS_MODULE

public func RoGetActivationFactory<Factory: IInspectable>(_ activatableClassId: HString) throws -> Factory {
private var IID_IActivationFactory: SUPPORT_MODULE.IID {
.init(Data1: 0x00000035, Data2: 0x0000, Data3: 0x0000, Data4: ( 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 )) // 00000035-0000-0000-C000-000000000046
}

public class IActivationFactory: SUPPORT_MODULE.IInspectable {
override public class var IID: SUPPORT_MODULE.IID { IID_IActivationFactory }

public func ActivateInstance() throws -> SUPPORT_MODULE.IInspectable {
return try perform(as: C_IActivationFactory.self) { pThis in
let instance = try ComPtrs.initialize { instanceAbi in
try CHECKED(pThis.pointee.lpVtbl.pointee.ActivateInstance(pThis, &instanceAbi))
}
return .init(instance!)
}
}
}

public func RoGetActivationFactory<Factory: IInspectable>(_ activatableClassId: StaticString) throws -> Factory {
var iid = Factory.IID
let (factory) = try ComPtrs.initialize(to: C_IInspectable.self) { factoryAbi in
try CHECKED(RoGetActivationFactory(activatableClassId.get(), &iid, &factoryAbi))
try activatableClassId.withHStringRef { activatableClassIdHStr in
try CHECKED(RoGetActivationFactory(activatableClassIdHStr, &iid, &factoryAbi))
}
}
return try factory!.queryInterface()
}

public func RoActivateInstance<Instance: IInspectable>(_ activatableClassId: HString) throws -> Instance {
let (instance) = try ComPtrs.initialize { instanceAbi in
try CHECKED(RoActivateInstance(activatableClassId.get(), &instanceAbi))
}
return try instance!.queryInterface()
}

// ISwiftImplemented is a marker interface for code-gen types which are created by swift/winrt. It's used to QI
// an IUnknown VTABLE to see whether we can unwrap this type as a known swift object. The class is marked final
Expand Down
25 changes: 25 additions & 0 deletions swiftwinrt/Resources/Support/Swift+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,31 @@ extension String {
let pwszBuffer: PCWSTR = WindowsGetStringRawBuffer(hString.get(), &length)
self.init(decoding: UnsafeBufferPointer(start: pwszBuffer, count: Int(length)), as: UTF16.self)
}

public func withHStringRef(_ body: (HSTRING?) throws -> Void) rethrows {
try self.withCString(encodedAs: UTF16.self) {
var hString: HSTRING?
var header: HSTRING_HEADER = .init()
try CHECKED(WindowsCreateStringReference($0, UInt32(self.count), &header, &hString))
try body(hString)
}
}
}

extension StaticString {
public func withHStringRef(_ body: (HSTRING?) throws -> Void) rethrows {
var buffer: C_BINDINGS_MODULE.StaticWCharArray_512 = .init()
try withUnsafeMutableBytes(of: &buffer.Data) { (bytes:UnsafeMutableRawBufferPointer) in
let bytesPtr = bytes.assumingMemoryBound(to: WCHAR.self)
self.withUTF8Buffer { utf8buffer in
try! CHECKED(MultiByteToWideChar(UInt32(CP_UTF8), 0, utf8buffer.baseAddress, Int32(utf8buffer.count), bytesPtr.baseAddress, Int32(bytes.count)))
}
var hString: HSTRING?
var header: HSTRING_HEADER = .init()
try CHECKED(WindowsCreateStringReference(bytesPtr.baseAddress, UINT32(self.utf8CodeUnitCount), &header, &hString))
try body(hString)
}
}
}

extension Bool {
Expand Down
10 changes: 6 additions & 4 deletions swiftwinrt/code_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -1920,7 +1920,7 @@ vtable);
{
interface_info factory_info{ factoryIface };
auto swift_name = get_swift_name(factory_info);
w.write("private static let %: %.% = try! RoGetActivationFactory(HString(\"%\"))\n",
w.write("private static let %: %.% = try! RoGetActivationFactory(\"%\")\n",
swift_name, abi_namespace(factoryIface), factory.type, get_full_type_name(type));
for (const auto& method : factoryIface->functions)
{
Expand All @@ -1941,10 +1941,12 @@ vtable);
{
auto base_class = type.base_class;

w.write("private static let _defaultFactory: %.IActivationFactory = try! RoGetActivationFactory(\"%\")\n",
w.support, get_full_type_name(type));
w.write("%public init() {\n", has_default_constructor(base_class) ? "override " : "");
{
auto indent = w.push_indent();
auto activateInstance = w.write_temp("try! RoActivateInstance(HString(\"%\"))", get_full_type_name(type));
auto activateInstance = "try! Self._defaultFactory.ActivateInstance()";
if (base_class)
{
w.write("super.init(fromAbi: %)\n", activateInstance);
Expand Down Expand Up @@ -1992,7 +1994,7 @@ public init<Composable: ComposableImpl>(
{
if (auto factoryIface = dynamic_cast<const interface_type*>(factory.type))
{
w.write("private static var _% : %.% = try! RoGetActivationFactory(HString(\"%\"))\n\n",
w.write("private static var _% : %.% = try! RoGetActivationFactory(\"%\")\n\n",
factory.type,
abi_namespace(factoryIface),
factory.type,
Expand Down Expand Up @@ -2277,7 +2279,7 @@ public init<Composable: ComposableImpl>(
static_info.attributed = true;

auto impl_name = get_swift_name(static_info);
w.write("private static let %: %.% = try! RoGetActivationFactory(HString(\"%\"))\n",
w.write("private static let %: %.% = try! RoGetActivationFactory(\"%\")\n",
impl_name,
abi_namespace(statics.type),
statics.type->swift_type_name(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ public final class PropertySet : WinRTClass, IObservableMap, IMap, IIterable, IP
override public func queryInterface(_ iid: test_component.IID) -> IUnknownRef? {
return super.queryInterface(iid)
}
private static let _defaultFactory: test_component.IActivationFactory = try! RoGetActivationFactory("Windows.Foundation.Collections.PropertySet")
override public init() {
super.init(try! RoActivateInstance(HString("Windows.Foundation.Collections.PropertySet")))
super.init(try! Self._defaultFactory.ActivateInstance())
}

private lazy var _IObservableMap: IObservableMapString_Any! = getInterfaceForCaching()
Expand Down Expand Up @@ -133,8 +134,9 @@ public final class StringMap : WinRTClass, IMap, IIterable, IObservableMap {
override public func queryInterface(_ iid: test_component.IID) -> IUnknownRef? {
return super.queryInterface(iid)
}
private static let _defaultFactory: test_component.IActivationFactory = try! RoGetActivationFactory("Windows.Foundation.Collections.StringMap")
override public init() {
super.init(try! RoActivateInstance(HString("Windows.Foundation.Collections.StringMap")))
super.init(try! Self._defaultFactory.ActivateInstance())
}

/// [Open Microsoft documentation](https://learn.microsoft.com/uwp/api/windows.foundation.collections.stringmap.lookup)
Expand Down Expand Up @@ -229,8 +231,9 @@ public final class ValueSet : WinRTClass, IObservableMap, IMap, IIterable, IProp
override public func queryInterface(_ iid: test_component.IID) -> IUnknownRef? {
return super.queryInterface(iid)
}
private static let _defaultFactory: test_component.IActivationFactory = try! RoGetActivationFactory("Windows.Foundation.Collections.ValueSet")
override public init() {
super.init(try! RoActivateInstance(HString("Windows.Foundation.Collections.ValueSet")))
super.init(try! Self._defaultFactory.ActivateInstance())
}

private lazy var _IObservableMap: IObservableMapString_Any! = getInterfaceForCaching()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public final class Deferral : WinRTClass, IClosable {
override public func queryInterface(_ iid: test_component.IID) -> IUnknownRef? {
return super.queryInterface(iid)
}
private static let _IDeferralFactory: __ABI_Windows_Foundation.IDeferralFactory = try! RoGetActivationFactory(HString("Windows.Foundation.Deferral"))
private static let _IDeferralFactory: __ABI_Windows_Foundation.IDeferralFactory = try! RoGetActivationFactory("Windows.Foundation.Deferral")
public init(_ handler: DeferralCompletedHandler!) {
super.init(try! Self._IDeferralFactory.CreateImpl(handler))
}
Expand Down Expand Up @@ -83,7 +83,7 @@ public final class MemoryBuffer : WinRTClass, IClosable, IMemoryBuffer {
override public func queryInterface(_ iid: test_component.IID) -> IUnknownRef? {
return super.queryInterface(iid)
}
private static let _IMemoryBufferFactory: __ABI_Windows_Foundation.IMemoryBufferFactory = try! RoGetActivationFactory(HString("Windows.Foundation.MemoryBuffer"))
private static let _IMemoryBufferFactory: __ABI_Windows_Foundation.IMemoryBufferFactory = try! RoGetActivationFactory("Windows.Foundation.MemoryBuffer")
public init(_ capacity: UInt32) {
super.init(try! Self._IMemoryBufferFactory.CreateImpl(capacity))
}
Expand Down Expand Up @@ -132,7 +132,7 @@ public final class Uri : WinRTClass, IStringable {
override public func queryInterface(_ iid: test_component.IID) -> IUnknownRef? {
return super.queryInterface(iid)
}
private static let _IUriEscapeStatics: __ABI_Windows_Foundation.IUriEscapeStatics = try! RoGetActivationFactory(HString("Windows.Foundation.Uri"))
private static let _IUriEscapeStatics: __ABI_Windows_Foundation.IUriEscapeStatics = try! RoGetActivationFactory("Windows.Foundation.Uri")
/// [Open Microsoft documentation](https://learn.microsoft.com/uwp/api/windows.foundation.uri.unescapecomponent)
public static func unescapeComponent(_ toUnescape: String) -> String {
return try! _IUriEscapeStatics.UnescapeComponentImpl(toUnescape)
Expand All @@ -143,7 +143,7 @@ public final class Uri : WinRTClass, IStringable {
return try! _IUriEscapeStatics.EscapeComponentImpl(toEscape)
}

private static let _IUriRuntimeClassFactory: __ABI_Windows_Foundation.IUriRuntimeClassFactory = try! RoGetActivationFactory(HString("Windows.Foundation.Uri"))
private static let _IUriRuntimeClassFactory: __ABI_Windows_Foundation.IUriRuntimeClassFactory = try! RoGetActivationFactory("Windows.Foundation.Uri")
public init(_ uri: String) {
super.init(try! Self._IUriRuntimeClassFactory.CreateUriImpl(uri))
}
Expand Down Expand Up @@ -289,7 +289,7 @@ public final class WwwFormUrlDecoder : WinRTClass, IIterable, IVectorView {
override public func queryInterface(_ iid: test_component.IID) -> IUnknownRef? {
return super.queryInterface(iid)
}
private static let _IWwwFormUrlDecoderRuntimeClassFactory: __ABI_Windows_Foundation.IWwwFormUrlDecoderRuntimeClassFactory = try! RoGetActivationFactory(HString("Windows.Foundation.WwwFormUrlDecoder"))
private static let _IWwwFormUrlDecoderRuntimeClassFactory: __ABI_Windows_Foundation.IWwwFormUrlDecoderRuntimeClassFactory = try! RoGetActivationFactory("Windows.Foundation.WwwFormUrlDecoder")
public init(_ query: String) {
super.init(try! Self._IWwwFormUrlDecoderRuntimeClassFactory.CreateWwwFormUrlDecoderImpl(query))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ public final class QueryOptions : WinRTClass {
super.init(fromAbi)
}

private static let _defaultFactory: test_component.IActivationFactory = try! RoGetActivationFactory("Windows.Storage.Search.QueryOptions")
override public init() {
super.init(try! RoActivateInstance(HString("Windows.Storage.Search.QueryOptions")))
super.init(try! Self._defaultFactory.ActivateInstance())
}

private static let _IQueryOptionsFactory: __ABI_Windows_Storage_Search.IQueryOptionsFactory = try! RoGetActivationFactory(HString("Windows.Storage.Search.QueryOptions"))
private static let _IQueryOptionsFactory: __ABI_Windows_Storage_Search.IQueryOptionsFactory = try! RoGetActivationFactory("Windows.Storage.Search.QueryOptions")
public init(_ query: CommonFileQuery, _ fileTypeFilter: AnyIIterable<String>!) {
super.init(try! Self._IQueryOptionsFactory.CreateCommonFileQueryImpl(query, fileTypeFilter))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ public final class Buffer : WinRTClass, IBufferByteAccess, IBuffer {
override public func queryInterface(_ iid: test_component.IID) -> IUnknownRef? {
return super.queryInterface(iid)
}
private static let _IBufferFactory: __ABI_Windows_Storage_Streams.IBufferFactory = try! RoGetActivationFactory(HString("Windows.Storage.Streams.Buffer"))
private static let _IBufferFactory: __ABI_Windows_Storage_Streams.IBufferFactory = try! RoGetActivationFactory("Windows.Storage.Streams.Buffer")
public init(_ capacity: UInt32) {
super.init(try! Self._IBufferFactory.CreateImpl(capacity))
}

private static let _IBufferStatics: __ABI_Windows_Storage_Streams.IBufferStatics = try! RoGetActivationFactory(HString("Windows.Storage.Streams.Buffer"))
private static let _IBufferStatics: __ABI_Windows_Storage_Streams.IBufferStatics = try! RoGetActivationFactory("Windows.Storage.Streams.Buffer")
/// [Open Microsoft documentation](https://learn.microsoft.com/uwp/api/windows.storage.streams.buffer.createcopyfrommemorybuffer)
public static func createCopyFromMemoryBuffer(_ input: test_component.AnyIMemoryBuffer!) -> Buffer! {
return try! _IBufferStatics.CreateCopyFromMemoryBufferImpl(input)
Expand Down
Loading

0 comments on commit 499c448

Please sign in to comment.