Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: How to expose/access WinUI Win32 interop APIs? (e.g. IWindowNative::get_WindowHandle) #199

Open
stackotter opened this issue Jan 6, 2025 · 4 comments

Comments

@stackotter
Copy link

I'm trying to access the window handle of a WinUI Window and I'm struggling to figure out how to generate bindings for IWindowNative::get_WindowHandle or even just call it via raw C APIs.

Is this something that's supported by swift-winrt? If so how should I modify my swift-cwinrt and swift-winui projections to generate bindings for IWindowNative? And if not are there any known workarounds?

The part that I'm finding tricky is that IWindowNative is defined in this weird idl directory which only defines a few other types, none of which I can find mentioned in any of the (now archived) pre-generated swift-winui family of bindings (which I searched for examples of bindings for similarly located symbols to no avail).

I've tried adding Microsoft.UI.Xaml.Window to swift-cwinrt's projections.json and regenerating but that didn't help (which I kinda expected given that the docs for IWindowNative::get_WindowHandle aren't in the regular namespaced part of the Windows App SDK docs).


For context, my actual goal is to set a minimum size for a WinUI window, and I've got all of the parts figured out other than getting a native window handle. I believe I need to get window handles to be able to map the window handle my hook receives back to the corresponding Window instance so that I can fetch the minimum size assigned to the window receiving the message.

I've been kinda vaguely trying to replicate this WinUI Window minimum size workaround without Win32 subclassing (cause I figured that that would probably make things even harder given that I have basically zero Windows development experience let alone Win32/WinRT development experience). To do it without Win32 subclassing I've adapted the hooking code from the wonderfully named MainRunLoopTickler and successfully received WM_GETMINMAXSIZE messages.

If anyone has any alternative suggestions for approaches I'd be greatly appreciative!

@stackotter
Copy link
Author

Here's what I have so far. Just including it as a bit more context around my current approach.

import WinSDK
import CWinRT
@_spi(WinRTInternal) import WindowsFoundation

let minSizeHook: HOOKPROC = { (nCode: Int32, wParam: WPARAM, lParam: LPARAM) in
    if nCode >= 0 {
        let ptr = UnsafeRawPointer(bitPattern: Int(lParam))?
            .assumingMemoryBound(to: CWPRETSTRUCT.self)
        if let msgInfo = ptr?.pointee, msgInfo.message == WM_GETMINMAXINFO {
            print("Received WM_GETMINMAXINFO")

            // I believe that I need to get CWinRT to generate a struct for `IWindowNative`
            // somehow?
            var value: __HWND
            _ = try! window._inner.perform(
                as: __x_ABI_CMicrosoft_CUI_CXaml_CIWindowNative.self // Doesn't exist
            ) { pThis in
                try! CHECKED(pThis.pointee.lpVtbl.pointee.get_WindowHandle(pThis, &handle))
            }
        }
    }
    return CallNextHookEx(nil, nCode, wParam, lParam)
}

_ = SetWindowsHookExW(WH_CALLWNDPROCRET, minSizeHook, nil, GetCurrentThreadId())

@tristanlabelle
Copy link
Contributor

Hi @stackotter . It is possible to query COM interfaces on swift-winrt-generated objects, but it's a little involved. In Arc, we do this by creating a WinRT component in C++, which takes the WinRT window type as a parameter, uses QueryInterface for IWindowNative in the C++ code, and calls the necessary methods. Alternatively, you may be able to define __x_ABI_CMicrosoft_CUI_CXaml_CIWindowNative manually in a C++ module, then get the IUnknown pointer in Swift and call QueryInterface. @stevenbrix might have more ideas.

@ktraunmueller
Copy link
Contributor

ktraunmueller commented Jan 21, 2025

@stackotter You probably already came across WinUIEx, but in case not, that repo (although C#) may have some solutions worked out for problems around missing features in WinUI (like the minimum window size) you may run into.

@stackotter
Copy link
Author

Thanks, I hadn't come across that yet! It looks very useful and it has given me some things to try

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants