Microsoft-ui-xaml: Question: How to get the HWND of a WinUI 3 Desktop app?

Created on 4 Jul 2020  路  9Comments  路  Source: microsoft/microsoft-ui-xaml

I created a WinUI desktop app, but it doesn't expose the underlying Window used. Instead I have a Window class that only exposes Title and Size. How can I get the win32 handle of the window?

Area-Desktop question winui3preview

Most helpful comment

Hi @jtbrower, @eklipse2k8, @Felix-Dev
There is COM interface called IWindowNative to get the HWND of a Window object. Unfortunately, the C#/WinRT projections need some improvements (already in-place for the Preview 2) to enable consume the COM Interfaced as it was spec'ed.

As you pointed the sample WinUI-3-Demo demo how to do it, but it's not the developer experience we are expecting.

All 9 comments

@eklipse2k8 See this comment by @jtbrower or this code:

IntPtr windowHandle = (App.Current as App).WindowHandle;

This will require additional code to written by developers as can be seen here.

Can this be a request to add a Handle property to the Window? For Desktop apps this seems like a bad workaround.

@eklipse2k8 I added another way in the post above.

Could you also confirm if the following code works?

Window w = new Window();
w.QueryInterface(IWindowInterop);
IntPtr hwnd = w.GetInterop<IWindowInterop>().Handle;

This code is specified in the WinUI Window spec document V1 here (I have not yet used WinUI 3 Desktop so I don't know for sure if this currently works).

Could you also confirm if the following code works?

Window w = new Window();
w.QueryInterface(IWindowInterop);
IntPtr hwnd = w.GetInterop<IWindowInterop>().Handle;

@Felix-Dev since I have a couple WinUI Desktop projects open I thought I would test out your method but cannot seem to locate the IWindowInterop interface or QueryInterface. If you tell me what assemblies / namespaces they are in I will test them out.

I stumbled upon another approach for obtaining the Window handle. @marb2000 pointed out here that his //Build demo showed how to obtain a it. I put it into a helper class below along with the other method I created using System.Diagnostics. I haven't been able to figure out the method @Felix-Dev shared yet but I am willing to bet that IWindowInterop is probably defined similar to how Miguel defined his.

//Grab a handle for a specific window
Window w = new Window();
var handle = w.GetHandle();

//Grab a handle for the Window associated with the current process
var currentProcMainWindowHandle = GetCurrentProcMainWindowHandle();
namespace Oceanside.Views.WinUI
{
    using Microsoft.UI.Xaml;
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using WinRT;

    public static class WindowHelpers
    {
        public static IntPtr GetCurrentProcMainWindowHandle()
        {
            using var process = Process.GetCurrentProcess();
            return process.MainWindowHandle;
        }

        public static IntPtr GetHandle(this Window window)
        {
            WindowWrapper windowWrapper = WindowWrapper.FromAbi(window.ThisPtr);
            return windowWrapper.WindowHandle;
        }

        [ComImport]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("EECDBF0E-BAE9-4CB6-A68E-9598E1CB57BB")]
        private interface IWindowNative
        {
            IntPtr WindowHandle { get; }
        }

        [Guid("EECDBF0E-BAE9-4CB6-A68E-9598E1CB57BB")]
        private class WindowWrapper : IWindowNative
        {
            [Guid("EECDBF0E-BAE9-4CB6-A68E-9598E1CB57BB")]
            public struct Vftbl
            {
                public delegate int _get_WindowHandle_0(IntPtr thisPtr, out IntPtr windowHandle);
                internal global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
                public _get_WindowHandle_0 get_WindowHandle_0;
                public static readonly Vftbl AbiToProjectionVftable;
                public static readonly IntPtr AbiToProjectionVftablePtr;

                static Vftbl()
                {
                    AbiToProjectionVftable = new Vftbl
                    {
                        IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
                        get_WindowHandle_0 = Do_Abi_get_WindowHandle_0
                    };
                    AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf<Vftbl>());
                    Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
                }

                private static int Do_Abi_get_WindowHandle_0(IntPtr thisPtr, out IntPtr windowHandle)
                {
                    windowHandle = default;
                    try
                    {
                        windowHandle = ComWrappersSupport.FindObject<IWindowNative>(thisPtr).WindowHandle;
                    }
                    catch (Exception ex)
                    {
                        return Marshal.GetHRForException(ex);
                    }
                    return 0;
                }
            }
            internal static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr)
            {
                return ObjectReference<Vftbl>.FromAbi(thisPtr);
            }

            public static implicit operator WindowWrapper(IObjectReference obj)
            {
                return (obj != null) ? new WindowWrapper(obj) : null;
            }

            protected readonly ObjectReference<Vftbl> _obj;
            public IObjectReference ObjRef => _obj;
            public IntPtr ThisPtr => _obj.ThisPtr;
            public ObjectReference<I> AsInterface<I>()
            {
                return _obj.As<I>();
            }

            public A As<A>()
            {
                return _obj.AsType<A>();
            }

            public WindowWrapper(IObjectReference obj) : this(obj.As<Vftbl>()) { }
            internal WindowWrapper(ObjectReference<Vftbl> obj)
            {
                _obj = obj;
            }

            public IntPtr WindowHandle
            {
                get
                {
                    Marshal.ThrowExceptionForHR(_obj.Vftbl.get_WindowHandle_0(ThisPtr, out var windowHandle));

                    return windowHandle;
                }
            }
        }
    }
}

@jtbrower

I haven't been able to figure out the method @Felix-Dev shared yet but I am willing to bet that IWindowInterop is probably defined similar to how Miguel defined his.

Indeed, @marb2000 is the best person here to speak on this as I just copied that code from the WinUI Windowing spec. It doesn't appear to me as if additional work by developers would be required here but apparently it's not working yet in Preview 1 at least, seeing as you couldn't get it to work by simply pasting this code into your WinUI Desktop app.

@Felix-Dev

It doesn't _appear_ to me as if additional work by developers would be required here but apparently it's not working yet in Preview 1 at least, seeing as you couldn't get it to work by simply pasting this code into your WinUI Desktop app.

Just to clarify, that the problem I encountered wasn't that I couldn't get it to work, it was the fact that I couldn't locate the required IWindowInterop interface or Window extension methods such as GetInterop or QueryInterface. With intellisense missing from the current WinUI version, I searched through github & google thinking I was missing something. The only result that github/google returns for IWindowInterop leads you back to this issue itself. Hopefully I am not overlooking something; (note that I am using .Net5.0 preview 6 with WinUI preview 1).

With the WinUI Windowing spec being just a spec, maybe it is specifying future intent?

Hi @jtbrower, @eklipse2k8, @Felix-Dev
There is COM interface called IWindowNative to get the HWND of a Window object. Unfortunately, the C#/WinRT projections need some improvements (already in-place for the Preview 2) to enable consume the COM Interfaced as it was spec'ed.

As you pointed the sample WinUI-3-Demo demo how to do it, but it's not the developer experience we are expecting.

What's my best option to do this from a C++/WinRT application?

Was this page helpful?
0 / 5 - 0 ratings