diff --git a/swiftwinrt/Resources/Support/IInspectable.swift b/swiftwinrt/Resources/Support/IInspectable.swift index 04fb211b..a08ceb53 100644 --- a/swiftwinrt/Resources/Support/IInspectable.swift +++ b/swiftwinrt/Resources/Support/IInspectable.swift @@ -79,28 +79,30 @@ public enum __ABI_ { public static func tryUnwrapFrom(raw pUnk: UnsafeMutableRawPointer?) -> AnyObject? { tryUnwrapFromBase(raw: pUnk) } + + internal static func queryInterface(_ pUnk: UnsafeMutablePointer?, _ riid: UnsafePointer?, _ ppvObject: UnsafeMutablePointer?) -> HRESULT { + guard let pUnk, let riid, let ppvObject else { return E_INVALIDARG } + ppvObject.pointee = nil + if riid.pointee == IUnknown.IID || + riid.pointee == IInspectable.IID || + riid.pointee == ISwiftImplemented.IID || + riid.pointee == IAgileObject.IID { + _ = pUnk.pointee.lpVtbl.pointee.AddRef(pUnk) + ppvObject.pointee = UnsafeMutableRawPointer(pUnk) + return S_OK + } + let swiftObj = AnyWrapper.tryUnwrapFrom(raw: pUnk) + if let customQueryInterface = swiftObj as? CustomQueryInterface, + let result = customQueryInterface.queryInterface(riid.pointee) { + ppvObject.pointee = result.detach() + return S_OK + } + return E_NOINTERFACE + } } internal static var IInspectableVTable: C_IInspectableVtbl = .init( - QueryInterface: { - guard let pUnk = $0, let riid = $1, let ppvObject = $2 else { return E_INVALIDARG } - ppvObject.pointee = nil - if riid.pointee == IUnknown.IID || - riid.pointee == IInspectable.IID || - riid.pointee == ISwiftImplemented.IID || - riid.pointee == IAgileObject.IID { - _ = pUnk.pointee.lpVtbl.pointee.AddRef(pUnk) - ppvObject.pointee = UnsafeMutableRawPointer(pUnk) - return S_OK - } - let swiftObj = AnyWrapper.tryUnwrapFrom(raw: pUnk) - if let customQueryInterface = swiftObj as? CustomQueryInterface, - let result = customQueryInterface.queryInterface(riid.pointee) { - ppvObject.pointee = result.detach() - return S_OK - } - return E_NOINTERFACE - }, + QueryInterface: { AnyWrapper.queryInterface($0, $1, $2) }, AddRef: { AnyWrapper.addRef($0) }, Release: { AnyWrapper.release($0) }, GetIids: { @@ -138,4 +140,4 @@ extension ComposableImpl where CABI == C_IInspectable { let vtblPtr = withUnsafeMutablePointer(to: &__ABI_.IInspectableVTable) { $0 } return .init(lpVtbl: vtblPtr) } -} \ No newline at end of file +} diff --git a/swiftwinrt/Resources/Support/IWeakReference.swift b/swiftwinrt/Resources/Support/IWeakReference.swift index d9155780..c600bc47 100644 --- a/swiftwinrt/Resources/Support/IWeakReference.swift +++ b/swiftwinrt/Resources/Support/IWeakReference.swift @@ -27,6 +27,19 @@ fileprivate class WeakReferenceWrapper: WinRTAbiBridgeWrapper?, _ riid: UnsafePointer?, _ ppvObject: UnsafeMutablePointer?) -> HRESULT { + guard let pUnk, let riid, let ppvObject else { return E_INVALIDARG } + switch riid.pointee { + case IID_IWeakReference: + _ = pUnk.pointee.lpVtbl.pointee.AddRef(pUnk) + return S_OK + default: + guard let obj = WeakReferenceWrapper.tryUnwrapFromBase(raw: pUnk) else { return E_NOINTERFACE } + let anyWrapper = __ABI_.AnyWrapper(obj)! + return __ABI_.AnyWrapper.queryInterface(try! anyWrapper.toABI { $0 }, riid, ppvObject) + } + } } fileprivate enum IWeakReferenceBridge: AbiBridge { @@ -43,17 +56,7 @@ fileprivate enum IWeakReferenceBridge: AbiBridge { } fileprivate var IWeakReferenceVTable: C_IWeakReferenceVtbl = .init( - QueryInterface: { pUnk, riid, ppvObject in - guard let pUnk, let riid, let ppvObject else { return E_INVALIDARG } - switch riid.pointee { - case IID_IWeakReference: - _ = pUnk.pointee.lpVtbl.pointee.AddRef(pUnk) - return S_OK - default: - guard let obj = WeakReferenceWrapper.tryUnwrapFromBase(raw: pUnk) else { return E_NOINTERFACE } - fatalError("\(#function): Not implemented: something like obj.QueryInterface") - } - }, + QueryInterface: { WeakReferenceWrapper.queryInterface($0, $1, $2) }, AddRef: { WeakReferenceWrapper.addRef($0) }, Release: { WeakReferenceWrapper.release($0) }, Resolve: { Resolve($0, $1, $2) } @@ -61,17 +64,19 @@ fileprivate var IWeakReferenceVTable: C_IWeakReferenceVtbl = .init( fileprivate func Resolve( _ this: UnsafeMutablePointer?, - _ iid: UnsafePointer?, - _ inspectable: UnsafeMutablePointer?>?) -> HRESULT { + _ riid: UnsafePointer?, + _ ppvObject: UnsafeMutablePointer?>?) -> HRESULT { + guard let this, let riid, let ppvObject else { return E_INVALIDARG } guard let weakReference = WeakReferenceWrapper.tryUnwrapFrom(abi: ComPtr(this)) else { return E_FAIL } - guard let iid, let inspectable else { return E_INVALIDARG } - if let target = weakReference.target { - _ = target - _ = iid - fatalError("\(#function): Not implemented: something like target.QueryInterface") - } - else { - inspectable.pointee = nil - return S_OK - } + ppvObject.pointee = nil + // https://learn.microsoft.com/en-us/windows/win32/api/weakreference/nf-weakreference-iweakreference-resolve(refiid_iinspectable): + // "If you try to resolve a weak reference to a strong reference for an object that is no longer available, + // then IWeakReference::Resolve returns S_OK, but the objectReference parameter points to null. + guard let target = weakReference.target else { return S_OK } + + let anyWrapper = __ABI_.AnyWrapper(target)! + var rawObject: UnsafeMutableRawPointer? = nil + let result = __ABI_.AnyWrapper.queryInterface(try! anyWrapper.toABI { $0 }, riid, &rawObject) + ppvObject.pointee = rawObject?.bindMemory(to: C_IInspectable.self, capacity: 1) + return result } diff --git a/swiftwinrt/Resources/Support/IWeakReferenceSource.swift b/swiftwinrt/Resources/Support/IWeakReferenceSource.swift index 2295ffc3..5a118344 100644 --- a/swiftwinrt/Resources/Support/IWeakReferenceSource.swift +++ b/swiftwinrt/Resources/Support/IWeakReferenceSource.swift @@ -20,6 +20,19 @@ fileprivate class WeakReferenceSourceWrapper: WinRTAbiBridgeWrapper?, _ riid: UnsafePointer?, _ ppvObject: UnsafeMutablePointer?) -> HRESULT { + guard let pUnk, let riid, let ppvObject else { return E_INVALIDARG } + switch riid.pointee { + case IID_IWeakReferenceSource: + _ = pUnk.pointee.lpVtbl.pointee.AddRef(pUnk) + return S_OK + default: + guard let obj = WeakReferenceSourceWrapper.tryUnwrapFromBase(raw: pUnk) else { return E_NOINTERFACE } + let anyWrapper = __ABI_.AnyWrapper(obj)! + return __ABI_.AnyWrapper.queryInterface(try! anyWrapper.toABI { $0 }, riid, ppvObject) + } + } } fileprivate enum IWeakReferenceSourceBridge: AbiBridge { @@ -36,17 +49,7 @@ fileprivate enum IWeakReferenceSourceBridge: AbiBridge { } fileprivate var IWeakReferenceSourceVTable: C_IWeakReferenceSourceVtbl = .init( - QueryInterface: { pUnk, riid, ppvObject in - guard let pUnk, let riid, let ppvObject else { return E_INVALIDARG } - switch riid.pointee { - case IID_IWeakReferenceSource: - _ = pUnk.pointee.lpVtbl.pointee.AddRef(pUnk) - return S_OK - default: - guard let obj = WeakReferenceSourceWrapper.tryUnwrapFromBase(raw: pUnk) else { return E_NOINTERFACE } - fatalError("\(#function): Not implemented: something like obj.QueryInterface") - } - }, + QueryInterface: { WeakReferenceSourceWrapper.queryInterface($0, $1, $2) }, AddRef: { WeakReferenceSourceWrapper.addRef($0) }, Release: { WeakReferenceSourceWrapper.release($0) }, GetWeakReference: { GetWeakReference($0, $1) }