Windows 8, where’d you put my HWND?!

Programmers seem to love abstractions, blissfully unaware of what’s happening under the covers. I guess that’s part of the appeal of .NET and its endless pile of abstractions. But if you’re anything like me you need to know what’s really going on. Even if you still end up using some of those abstractions, having a sense for what lives underneath can help you debug your code and ultimately create better software.

Today I want to share just one little-known fact about Windows 8 apps and that has to do with windows. Traditionally, each desktop application on Windows had at least one top-level window created via the CreateWindow function and represented by an HWND – a window handle. It wasn’t hard to see that .NET Windows Forms apps or even WPF apps still relied on an HWND for each top-level window that appeared on the desktop.

But in this brave new Metro world where everything is so fast and fluid it seems that developers are again gloriously ignorant of the fact that each app still has an HWND. I can’t really blame them as it’s pretty well hidden, but it’s still there. A little perspective again comes in handy. If you have any experience writing Windows services you will know that you are just a guest inside your own process. The same is true of Metro apps. As soon as your application’s process is created, the clock starts ticking. If you don’t hand over the wheel to the Windows Runtime, then before long Windows will shoot you in the head and your process is gone.

It begins, at least for CRT-based applications (any app produced with Visual C++) in good-old wWinMain. Yes, the default project templates try to hide wWinMain and replaces it with a silly main function designed to look like .NET but which just wastes memory and processor cycles. Anyway, the way your app relinquishes control to the Windows Runtime is by calling the static (in the C++/CX sense) CoreApplication::Run function. Your app simply implements the IFrameworkViewSource and IFrameworkView interfaces and the Windows Runtime will let you know when it needs your attention. Of course, if you’re writing a XAML based app then this is all implemented for you – another abstraction – but it’s all still there behind the scenes.

Regardless of whether you’re writing a “CoreApplication” directly or using the XAML framework, your app will have a top-level window represented by the CoreWindow class. You cannot create a CoreWindow yourself but the Windows Runtime graciously creates one for you. Once your app is up and running (specifically any time after your IFrameworkView::SetWindow implementation is called) you can call the static CoreWindow::GetForCurrentThread function to get hold of it.

auto w = CoreWindow::GetForCurrentThread();

Now it gets a little trickier. You see, there are some things a particular Windows Runtime object would rather not share with you but might want to share with someone else. Such discrimination is provided through cloaked interfaces that are not included in the Windows Runtime metadata, and not exposed by your friendly IInspectable interface. You have to use good old QueryInterface to discover whether such a cloaked interface is being offered. Of course, you first need to know what to query for. I’ll save you the trouble of guessing. Here it is:

struct __declspec(uuid("45D64A29-A63E-4CB6-B498-5781D298CB4F")) __declspec(novtable)
ICoreWindowInterop : IUnknown
    virtual HRESULT __stdcall get_WindowHandle(HWND * hwnd) = 0;
    virtual HRESULT __stdcall put_MessageHandled(unsigned char) = 0;

You can now crack open your CoreWindow with reinterpret_cast to reveal IUnknown and then query for the ICoreWindowInterop interface:

ComPtr<ICoreWindowInterop> interop;
HR(reinterpret_cast<IUnknown *>(w)->QueryInterface(interop.GetAddressOf()));

Now it’s a simple matter of calling the get_WindowHandle virtual function to get your app’s HWND.

HWND hwnd;

Don’t believe me? Just declare your old friend GetWindowText from USER32 and you will be rewarded with the window’s title, which the Windows Runtime sets based on information in your app’s package manifest.

extern "C"
int __stdcall GetWindowTextW(HWND hwnd, PWSTR text, int count);

WCHAR text[1024];
GetWindowTextW(hwnd, text, _countof(text));

So what can you do with this HWND? Well not very much. The reality is that everything on Windows 8 is rendered with Direct3D. Even your aging GDI app is ultimately composited together with other windows and presented to the screen as if the whole desktop were one giant DirectX application, and in some ways that’s what it is.

So even though you can get the HWND for your app, you already have access to the window’s Direct3D surface which is far more powerful than anything you could do with the HWND on your own. So why does this cloaked interface exist? Why to allow Direct3D to get your HWND of course! Oh, and ICoreWindowInterop exists on Windows Phone 8 as well.

11 thoughts on “Windows 8, where’d you put my HWND?!

  1. phi

    To be honest, I’m more than happy that we’re seeing the disappearance of the HWND. I’ve never liked it. More to the point, i’ve never liked its name. It has nothing of a HANDLE. It should have been named something like WindowId.
    It has nothing of a handle because it offers no guarantee. You can have an HWND of a window, that doesn’t stop anyone else to call a DestroyWindow() on that window, even if you were trying to manipulate it. The right way would have been to have a sort of GetHWND() and ReleaseHWND() (or better : CloseHandle()). Just my opinion, of course.

  2. Dusan Jovanovic

    Are we going to see truly new Windows in our lifetime I wonder sometimes ?

    HWND plainly revelas how wrong the whole WIN32 architecture is … but it is legacy and it is here to stay.
    Or not? I am hoping (sincerely) W8 is the first step towards Windows Next. Without HWND and without every Window receiving and filtering through every message in order to (usually) process just a single one.

    1. Kenny Kerr Post author

      It’s just an implementation detail of Metro apps and it happens to be very efficient so I don’t really see any urgent need to replace it with something new and unproven.

      1. Dusan Jovanovic

        @Kenny then it can be perhaps replaced with something old and proven, like X-Win for example ? In any case, I think W9 will contain no HWND. In any case no ridiculous Win32 message pump.

  3. Jieke Zhu

    Personal opinion.
    I love HWND. First, the name means very well the handle of the window.
    Second, it’s a amazing design of the use of HWND and HANDLE.
    Third, it’s a powerful stuff for us to get control of the physical window, to draw anything onto screen.
    Fourth, it’s part of Windows core, this can’t be changed at present.

    Hi guys,
    I tried these steps to get the HWND, but failed. About ICoreWindowInterop, I just add the codes below to my file. Is this right ? Do I need to use another way to define interface ICoreWindowInterop ? Thanks in advance for any reply.

    struct __declspec(uuid(“45D64A29-A63E-4CB6-B498-5781D298CB4F”)) __declspec(novtable)
    ICoreWindowInterop : IUnknown
    virtual HRESULT __stdcall get_WindowHandle(HWND * hwnd) = 0;
    virtual HRESULT __stdcall put_MessageHandled(unsigned char) = 0;

    1. DBJ

      Well here we are in 2015 Jan and in the era of Windows 10 🙂

      And WinRT API … and still I am not clear is anybody clear (including MSFT) about the future of HWND?

  4. David

    what is the variable HR in the line “HR(interop->get_WindowHandle(&hwnd));”? does it require a namespace?

  5. Ben

    I would add that it’s not true that you can’t do anything with a HWND, because you may have native code that does things with it that you want to keep working. What would worry me more is that even if you did try to render to it, is the Metro stuff hijacking the window with directx.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s