|
| 1 | +import CWinRT |
| 2 | +import WinAppSDK |
| 3 | +import WinSDK |
| 4 | +import WinUI |
| 5 | +import WindowsFoundation |
| 6 | + |
| 7 | +public func getWindowIDFromWindow(_ hWnd: HWND?) -> WinAppSDK.WindowId { |
| 8 | + HWNDInterop.shared.getWindowIDFromWindow(hWnd) |
| 9 | +} |
| 10 | + |
| 11 | +public func getWindowFromWindowId(_ windowID: WinAppSDK.WindowId) -> HWND? { |
| 12 | + HWNDInterop.shared.getWindowFromWindowId(windowID) |
| 13 | +} |
| 14 | + |
| 15 | +extension WinAppSDK.AppWindow { |
| 16 | + /// Returns the window handle for the app window. |
| 17 | + public func getHWND() -> HWND? { |
| 18 | + HWNDInterop.shared.getWindowFromWindowId(id) |
| 19 | + } |
| 20 | +} |
| 21 | + |
| 22 | +extension WinUI.Window { |
| 23 | + /// Returns the window handle for the window. |
| 24 | + /// |
| 25 | + /// - Note: This is a relatively expensive operation, particularly due to its use |
| 26 | + /// of the `appWindow` getter. If an `AppWindow` is already available, prefer to |
| 27 | + /// use `getHWND()` on that instead; better yet, if the window handle will be used |
| 28 | + /// frequently, assign it to a stored property, as it will not change during the |
| 29 | + /// lifetime of the window. |
| 30 | + public func getHWND() -> HWND? { |
| 31 | + // The appWindow can become nil when a Window is closed. |
| 32 | + guard let appWindow else { return nil } |
| 33 | + return appWindow.getHWND() |
| 34 | + } |
| 35 | +} |
| 36 | + |
| 37 | +private struct HWNDInterop { |
| 38 | + private typealias pfnGetWindowIdFromWindow = @convention(c) ( |
| 39 | + HWND?, UnsafeMutablePointer<__x_ABI_CMicrosoft_CUI_CWindowId>? |
| 40 | + ) -> HRESULT |
| 41 | + private typealias pfnGetWindowFromWindowId = @convention(c) ( |
| 42 | + __x_ABI_CMicrosoft_CUI_CWindowId, UnsafeMutablePointer<HWND?>? |
| 43 | + ) -> HRESULT |
| 44 | + private var hModule: HMODULE! |
| 45 | + private var getWindowIDFromWindow_impl: pfnGetWindowIdFromWindow! |
| 46 | + private var getWindowFromWindowID_impl: pfnGetWindowFromWindowId! |
| 47 | + |
| 48 | + static let shared = HWNDInterop() |
| 49 | + |
| 50 | + init() { |
| 51 | + "Microsoft.Internal.FrameworkUdk.dll".withCString(encodedAs: UTF16.self) { |
| 52 | + hModule = GetModuleHandleW($0) |
| 53 | + if hModule == nil { |
| 54 | + hModule = LoadLibraryW($0) |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + if let pfn = GetProcAddress(hModule, "Windowing_GetWindowIdFromWindow") { |
| 59 | + getWindowIDFromWindow_impl = unsafeBitCast(pfn, to: pfnGetWindowIdFromWindow.self) |
| 60 | + } |
| 61 | + |
| 62 | + if let pfn = GetProcAddress(hModule, "Windowing_GetWindowFromWindowId") { |
| 63 | + getWindowFromWindowID_impl = unsafeBitCast(pfn, to: pfnGetWindowFromWindowId.self) |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | + fileprivate func getWindowIDFromWindow(_ hWnd: HWND?) -> WinAppSDK.WindowId { |
| 68 | + var windowID = __x_ABI_CMicrosoft_CUI_CWindowId() |
| 69 | + let hr: HRESULT = getWindowIDFromWindow_impl(hWnd, &windowID) |
| 70 | + if hr != S_OK { |
| 71 | + fatalError("Unable to get window ID") |
| 72 | + } |
| 73 | + return .init(value: windowID.Value) |
| 74 | + } |
| 75 | + |
| 76 | + fileprivate func getWindowFromWindowId(_ windowID: WinAppSDK.WindowId) -> HWND? { |
| 77 | + var hWnd: HWND? |
| 78 | + let hr: HRESULT = getWindowFromWindowID_impl(.from(swift: windowID), &hWnd) |
| 79 | + if hr != S_OK { |
| 80 | + fatalError("Unable to get window from window ID") |
| 81 | + } |
| 82 | + return hWnd |
| 83 | + } |
| 84 | +} |
0 commit comments