How can I detect whether the Game Bar is covering my window?


Pressing the Win+G hotkey opens the Game Bar, which lets you record game clips and screenshots. Actually, I use it a lot even for programs that aren't games: It's great for taking video clips of a bug.

Anyway, maybe you have a program that wants to know when the Game Bar is on screen. For example, if you're a game, you may want to pause the game automatically when the user is trying to configure their screen capture.

If you are writing a Store app, you can register for Game Bar events. Here's the short version for C# apps:

if (Windows.Gaming.UI.GameBar.Visible) {
  the game bar is visible;
}

if (Windows.Gaming.UI.GameBar.IsInputRedirected) {
  the game bar has input;
}

Windows.Gaming.UI.GameBar.VisibilityChanged +=
    (s, e) => { the visibility changed };
Windows.Gaming.UI.GameBar.IsInputRedirectedChanged +=
    (s, e) => { the input state changed };

(Of course, you can avoid having to type Windows.Gaming.UI all the time by using the using statement, but I'm writing it out just to make it explicit what's going on.)

If you are a desktop app, you will have to talk to the ABI. It's not too difficult, although it is a bit more tedious.

Continuing our crash course in projection:

Call static method
ABI IWidgetStatics* widgetStatics;
GetActivationFactory(L"Widget", &widgetStatics);
widgetStatics->Foo();
C++/CX Widget::Foo();
C# Widget.Foo();
JavaScript Widget.foo();

At the ABI level, static members of a Windows Runtime class are represented as instance members of the class's activation factory. By convention, the interface name for static members is the runtime class name, followed by the word Statics.

Okay, we now know just enough to be dangerous. Start with the scratch program and make these changes. (Remember, Little Programs do little to no error checking.)

#include <wrl/client.h>
#include <wrl/event.h>
#include <wrl/wrappers/corewrappers.h>
#include <windows.gaming.ui.h>
#include <EventToken.h>
#include <tchar.h> // Huh? Why are you still using ANSI?

namespace WRL = Microsoft::WRL;
namespace awf = ABI::Windows::Foundation;
namespace gameui = ABI::Windows::Gaming::UI;

WRL::ComPtr<gameui::IGameBarStatics> g_gameBarStatics;
boolean g_isVisible;
boolean g_isInputRedirected;
EventRegistrationToken g_tokenVisibility;
EventRegistrationToken g_tokenInput;

After including a few header files and declaring some namespace aliases, we create a few global variables to keep track of our state. In a real program, these would probably be instance members of some C++ class, but I'm being lazy.

void CheckGameBarVisibility(HWND hwnd)
{
    boolean isVisible;
    g_gameBarStatics->get_Visible(&isVisible);
    if (g_isVisible != isVisible)
    {
        g_isVisible = isVisible;
        InvalidateRect(hwnd, nullptr, TRUE);
    }
}

void CheckGameBarInput(HWND hwnd)
{
    boolean isInputRedirected;
    g_gameBarStatics->get_IsInputRedirected(&isInputRedirected);
    if (g_isInputRedirected != isInputRedirected)
    {
        g_isVisible = isVisible;
        InvalidateRect(hwnd, nullptr, TRUE);
    }
}

These two little functions read the current visibility and input redirection states of the game bar, and if they changed, we invalidate the window. We learned about property access a little while ago. In our case, the properties are static, so the property accessors live on the Statics interface.

BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
  Windows::Foundation::GetActivationFactory(WRL::Wrappers::HStringReference(
    RuntimeClass_Windows_Gaming_UI_GameBar).Get(), &g_gameBarStatics);

  auto visibilityHandler = WRL::Callback<awf::IEventHandler<IInspectable*>>(
    [hwnd](IInspectable*, IInspectable*)
    {
      CheckGameBarVisibilty(hwnd);
      return S_OK;
    });
  g_gamebarStatics->add_VisibilityChanged(visibilityHandler.Get(), &g_tokenVisibility);

  auto inputHandler = WRL::Callback<awf::IEventHandler<IInspectable*>>(
    [hwnd](IInspectable*, IInspectable*)
    {
      CheckGameBarInput(hwnd);
      return S_OK;
    });
  g_gamebarStatics->add_IsInputRedirectedChanged(inputHandler.Get(), &g_tokenInput);

  CheckGameBarVisibility(hwnd);
  CheckGameBarInput(hwnd);
  return TRUE;
}

We create the game bar statics by asking for the IGameBarStatics interface from the activation factory. From there, we register two event handlers, one to be called when the visibility changes, and another to be called when input redirection changes. In both cases, we respond to the event by checking the new visiblity or input redirection state.

After registering the handlers, we manually check the visibility and input to get the initial values set up properly.

void
OnDestroy(HWND hwnd)
{
  g_gameBar->remove_VisibilityChanged(g_tokenVisibility);
  g_gameBar->remove_IsInputRedirectedChanged(g_tokenInput);
  g_gameBar.Reset();
  PostQuitMessage(0);
}

Naturally, we need to clean up when we're done.

void
PaintContent(HWND hwnd, PAINTSTRUCT *pps)
{
  PCTSTR visibleMessage =
    g_isVisible ? TEXT("GameBar is visible")
                : TEXT("GameBar is not visible");

  TextOut(pps->hdc, 0, 0, visibleMessage, _tcslen(visibleMessage));

  PCTSTR inputMessage =
    g_isInputRedirected ? TEXT("GameBar has taken input")
                        : TEXT("GameBar does not have input");

  TextOut(pps->hdc, 0, 20, inputMessage, _tcslen(inputMessage));
}

Our Paint­Content function prints the current state of the game bar: Is it visible? Does it have input?

And that's it. Run this program, press the Win+G hotkey to call up the game bar, and observe that the program updates its window to reflect the game bar state.

Comments (25)
  1. SimonRev says:

    Am I the only one who feels vaguely guilty — like I am lying under oath — when I check the “I solemnly swear that ‘Visual Studio’ is a game” checkbox that appears when you press Win+G?

    1. pc says:

      It’s hard to really nail down a good definition for “game”. I’ve heard good arguments for things like Stack Overflow and even Facebook as each being a “game” by some reasonable definitions. I see no reason why Visual Studio couldn’t be a game.

      Especially as sometimes one has a tough time with the boss fights…

      1. Kevin Puetz says:

        I’m not seeing a problem here – VS even has achievements! https://channel9.msdn.com/achievements/visualstudio

      2. Damien says:

        And, of course, the achievements you can earn – https://channel9.msdn.com/achievements/visualstudio

  2. Damien says:

    Sorry – pet peeve of mine – “… by using the using statement”. No, you cannot. The using statement is used to clean up resources by calling Dispose at the end of its embedded statement. You can simplify your use of namespaces by using a using directive.

    1. Nick says:

      There are two uses of the using keyword in C#. Raymond is referring to the one where you declare you’re using namespaces at the top of the file, like using System; or using System.Linq;.

      1. Nick says:

        Oh I see now, sorry.

  3. skSdnW says:

    No dice roll on the ComPtr class? My problem with all of this is that if I go to MSDN.com and search for “IGameBarStatics” I get zero results. MSDN assumes that nobody uses plain C++ anymore.

    Also, you can just change _tcslen to lstrlen and the tchar.h issue would go away although it is the only thing in this post that is still the oldnewthing ;)

    1. Darran Rowe says:

      Yeah, you have to balance between knowing the ABI and the projection to get the documentation on these things. It is easy enough to piece things together from the headers, but having to look through the headers is the problem.

    2. When I need to find documentation for it, I usually fire up ILSpy and open Windows.winmd with it (with Windows 10 SDK it’s in UnionMetadata folder). You can observe all the interface names, including aggregation, activation and static factories there, along with name overloading too.

  4. Mackenzie Zastrow says:

    Can you do the same from C# if you’re not writing a Store app?

    I know there’s https://github.com/kennykerr/modern for C++, I wonder if there’s something for C#. (I tried searching, but couldn’t find anything).

  5. Matteo Italia says:

    Ah, but now you cannot film the heisenbug that happens only in the “game bar not shown” branch!

  6. 12BitSlab says:

    If a developer wanted to take the stance that their software is not a game or that the developer did not want anything more than just a screen shot taken of the software, these techniques would make it trivial to stop the recording. Simply minimize the software, make the windows invisible, etc.

    1. Joshua says:

      Hey check out this great game called Remote Desktop.

    2. xcomcmdr says:

      Don’t give evil people ideas ! :o

  7. Drak says:

    Thank you for writing out the namespace, Raymond. I get really annoyed when I’m looking for hints how to do stuff on the internet, and people post some code without any namespaces in it at all (also no Using stateme… uh directives). Trying to figure out all the namespaces for their stuff is … bleh.

    1. RKZENITH says:

      Agreed. That using directive is one of the worst design decisions on the language side of .NET. It allows poor developers, who hardly understand the code while writing it, to take shortcuts that make it more difficult for even skilled developers during subsequent maintenance cycles. For every second saved by not typing out just enough for Intellisense to pick up what you were going for, an hour is squandered trying to figure out _which_ namespace some random object is coming from.

  8. xcomcmdr says:

    I’d like to use the GameBar’s ability to take screenshot of fullscreen games via an API (preferably in a .NET C# app), but I have a hard time figuring out if it is possible. It seems it isn’t. Or at least, it isn’t documented.

    All the examples I can find are :
    – using GDI+ to take a screenshot of the desktop (which usually results in a black screenshot)
    – using Windows.Media.Capture.ScreenCapture (only available on Windows Phone 8.1 :()
    – using convoluted DirectX hooking APIs à la Fraps. Seems overly complicated. I’d like to avoid that.
    – using the Windows Media 9 Screen Capture codec… Hum, I don’t think it’s what I want. Plus, it’s very old.

  9. Azarien says:

    Now this is a new level of API uglyness.

    1. That’s because we’re using the raw ABI, which as another commenter noted, was not intended for human consumption. Humans are intended to use one of the projections, such as C++/CX or Modern C++.

      1. Now, if that was the case, wouldn’t projections be available for desktop applications (and their requirements like dynamic loading) too? :)

        We had to write a whole lot of raw ABI code since our application still works on Windows XP, but we wanted to enable additional functionality if you happen to run on Windows 10 (e. g. Speech Recognition). That code is all shared with WinRT application version too. C++/CX doesn’t really allow your binary to work on XP.

        1. Adam says:

          @Tautvydas Zilys Could you refactor the platform specific functionality into its own DLL compiled with C++/CX, and then dynamically load the dlls based on platform?

          1. Well, that was one of the options we considered, but we went against it because we would have to invent a C API for all of the interop with the DLL (or something like COM, which would kinda defeat the purpose) as we’d have to link the DLL against different CRT (our main app is still built with VS2010). We went with pure COM approach since we thought that would allow us to write less code. Error handling is super annoying in C++/CX anyway, so it’s not like it was that much harder. I think we made the right call. I just thought it was funny that Raymond claimed that those APIs are not meant for human consumption.

        2. Ivan K says:

          Meh, if you’re still targeting an unsupported version of the OS then you might have to put up with some ugliness as a trade-off. Like cross platform code. You could roll your own projection or adapter or whatevs.

  10. Richard says:

    Why doesn’t the game bar work with my mfc application? It comes up and I can press record but it says “Nothing to record. Play some more” after several seconds.

Comments are closed.

Skip to main content