Search code examples
c#c++windows-8windows-rt

Closing the Windows 8 Charm Bar


I have a Surface Pro that I need to "lock down" as a type of Kiosk mode. I am aware that an update is on its way for "Kiosk Mode".. however I need to do this before that.

I have searched all over the internet, but it appears that you cannot disable the Charm bar from a swipe on the screen. I have found ways to disable trackpads.. but unfortunately, since this tablet will be used without a keyboard, I need to disable the Charm bar.

My new thought is to move the entire Charm bar HWND thousands of pixels off screen, or, maybe set a windows style on it so that it doesn't appear. I have attempted to use Spy++ and a custom EnumWindows based console app to give me some Window handles.. however I can't keep the Charm bar open long enough for these to take effect.

So my question is: How can I locate the Window Handle (HWND) for the Charm Bar in Windows 8? Or, how can I get a reference to the Charm bar some other way in order to throw a SetWindowLong or SetWindowPos at it?


Solution

  • In fact, I have found a way to do this (apparently, no one else has :/).

    For those wondering, software like "Start8" and "SkipMetroSuite" poll key presses to stop the Charm Bar. They literally simulate the keypresses to close it within a tight loop.

    I have found (what I think is) a better way.

    First up... some WinAPI functions:

    using System.Runtime.InteropServices;
    ....
    
    private enum WindowShowStyle : uint
    {  // find more info at http://stackoverflow.com/a/8210120/1245420
       Hide = 0, ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3,
       ShowNormalNoActvate = 4, Show = 5, Minimize = 6, ShowNoActivate = 8,
       Restore = 9, ShowDefault = 10, ForceMinimized = 11
    }
    
    [DllImport("user32.dll", SetLastError = true)]
    static extern System.IntPtr FindWindow(string lpClassName, string lpWindowName);
    
    [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
    static extern System.IntPtr FindWindowByCaption(System.IntPtr ZeroOnly, string lpWindowName);
    
    [DllImport("user32.dll")]
    static extern bool ShowWindow(System.IntPtr hWnd, WindowShowStyle nCmdShow);
    

    So the problem first up, is the Charm Bar. The Window title for this turns out to be, Charm Bar. Spawning a thread that continually looks for this window and hides it works beautifully. So I spawn a thread, and continually poll it:

    System.Threading.Tasks.Task.Factory.StartNew(() => {
        while (true) {
            System.IntPtr hWndCharmBar = FindWindowByCaption(System.IntPtr.Zero, "Charm Bar");
            ShowWindow(hWndCharmBar, 0);
            System.Threading.Thread.Sleep(100); // sleep for a bit
        }
    });
    

    This works well and gives the added benefit of making the Charm Bar continue to work when the app is closed. The Thread.Sleep is there to stop the thread smashing the CPU - but the delay also allows for the Charm Bar to appear for a split second. I am yet to successfully open the Charm Bar and press a button quick enough before the thread hides it again though, so this is fine. Lowering the sleep time obviously makes this quicker.

    The other issue with Windows 8 is that if you have some sort of slider (in my app, I have a ListBox containing images for a gallery) then you can actually slide to the side of the screen... hold your finger there, and access the taskbar...

    So.. the next part is closing the task bar:

    IntPtr hWndTray = FindWindow("Shell_TrayWnd", null);
    ShowWindow(hWndTray, 0);
    

    ..then I show it again on app close:

    IntPtr hWndTray = FindWindow("Shell_TrayWnd", null);
    ShowWindow(hWndTray, 1);
    

    Functionally, this is all I needed for my app. Hope that helps someone.