WinSDK/COM interop: value of type 'IInitializeWithWindow' has no member 'lpVtbl'

I am trying to integrate this piece of code (copied from swift-cross-ui) into my Windows app project:

import WinSDK

import WindowsFoundation

class SwiftIInitializeWithWindow: WindowsFoundation.IUnknown {
    
    override class var IID: WindowsFoundation.IID {
        WindowsFoundation.IID(
            Data1: 0x3E68_D4BD,
            Data2: 0x7135,
            Data3: 0x4D10,
            Data4: (0x80, 0x18, 0x9F, 0xB6, 0xD9, 0xF3, 0x3F, 0xA1)
        )
    }

    func initialize(with hwnd: HWND) throws {
        _ = try perform(as: IInitializeWithWindow.self) { pThis in
            try CHECKED(pThis.pointee.lpVtbl.pointee.Initialize(pThis, hwnd))
        }
    }
}

The compiler says

E:\sandbox\ktraunmueller\compositor\Sources\Win\WinSupport\Sources\Windows\Com+Interop.swift:19:39: error: value of type 'IInitializeWithWindow' has no member 'lpVtbl'
            try CHECKED(pThis.pointee.lpVtbl.pointee.Initialize(pThis, hwnd))
                        ~~~~~~~~~~~~~ ^~~~~~

Looking up the definition (ctrl-clicking IInitializeWithWindow opens WinSDK.Shell.swiftinterface) shows that the lpVtbl property is defined, however:

public struct IInitializeWithWindow {

    public init()

    public init(lpVtbl: UnsafeMutablePointer<IInitializeWithWindowVtbl>!)

    public var lpVtbl: UnsafeMutablePointer<IInitializeWithWindowVtbl>!
}

What am I missing?

Thanks in advance.

Edit: I’m on a fairly recent 6.3-dev TBC toolchain (20250930.2)

>swift -version
Swift version 6.3-dev (LLVM 75c6640ca938538, Swift 761b88fe9ad462c)
Target: aarch64-unknown-windows-msvc
Build config: +assertions

Do you have C++ interop enabled? If so, I would expect the COM class/interface to be projected directly onto pThis instead of indirectly through .pointee.lpVtbl.

Yes, C++ interop should be enabled:

cmake_minimum_required(VERSION 3.29)

add_library(WinSupport STATIC)

...
target_compile_options(WinSupport PRIVATE
    -cxx-interoperability-mode=default
)
...

And no, the type of pThis is UnsafeMutablePointer<IInitializeWithWindow>:

E:\sandbox\ktraunmueller\compositor\Sources\Win\WinSupport\Sources\Windows\Com+Interop.swift:20:31: error: value of type 'UnsafeMutablePointer<IInitializeWithWindow>' has no member 'Initialize'
            try CHECKED(pThis.Initialize(hwnd))
                        ~~~~~ ^~~~~~~~~~

(Note sure if this matters, but technically using the COM moniker wasn’t correct on my side, this is actually WinRT, not COM)

I think this is a swift-windowsfoundation / swift-winrt issue. I will take this over to the swift-winrt github.

When C++ interop is enabled, the Windows headers don't include a lpVtbl member in COM types because it's the vtable of the C++ class instead. So if the type is projected into Swift as UnsafeMutablePointer<ISomething>, try pThis.pointee.Initialize(hwnd) instead?

Aaah, right, I was trying to invoke the API through the C-style interface, when actually the #if defined(__cplusplus) branch is active in my case:

Now I am getting

E:\sandbox\ktraunmueller\compositor\Sources\Win\WinSupport\Sources\Windows\Com+Interop.swift:20:39: error: 'Initialize' is unavailable: virtual function is not available in Swift because it is pure
            try CHECKED(pThis.pointee.Initialize(hwnd))
                                      ^~~~~~~~~~
C:\Program Files (x86)\Windows Kits\10\\include\10.0.22000.0\\um\shobjidl_core.h:32191:43: note: 'Initialize' has been explicitly marked unavailable here
        virtual HRESULT STDMETHODCALLTYPE Initialize(

I tried switching over my project to C (from C++)

cmake_minimum_required(VERSION 3.29)
project(WinInterop LANGUAGES C)

and call through the C style API, but that gives the original error (hinting that I am still compiling the module with __cplusplus defined).

But this already helped me a lot, thanks for pointing me in the right direction!

1 Like