tags:

views:

242

answers:

3

I have a Windows app that uses the AppBar API to install as an application bar at the top of the screen (similar to the Windows task bar itself). This works great and the desktop size is adjusted accordingly, so my application is always visible.

However, if the user choose 'Show Desktop' (Windows+D), my application is hidden. Does anyone know of a way to trap 'Show Desktop' so I can ensure my application stays visible (I assume that Windows enumerates all top-level windows and hides them with ShowWindow(SW_HIDE).

A: 

I was under the impression that setting the window as a topmost window (via SetWindowPos and the HWND_TOPMOST flag) prevented the desktop from covering it. Windows+D goes through minimizing all windows, and then covering up those that can't be minimized by raising the desktop in the z-order (well, it did at one point anyway). I belive you can make a window unminimizable by not passing WS_MINIMIZEBOX to CreateWindowEx, or using WS_EX_TOOLWINDOW though I'm not 100% on that part.

A much heavier handed approach would be to hook the global keyboard using SetWindowsHookEx and a KeyboardProc. This will have a deleterious effect on the user experience.


I went and coded up a really simple example of what I'm talking about. The following code makes a window that is not minimized OR covered by a user hitting Windows+D. Note that on Windows 7, gadgets on the desktop can still be brought above it; which I can't really explain.

#include <windows.h>
#include <tchar.h>

#define WIN_TITLE _T("Resists Win+D Window")
#define WIN_CLASS _T("Resists Win+D Class")

LRESULT CALLBACK CustomWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    //Special behavior goes here

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

HWND CreateMainWindow(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = CustomWndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = WIN_CLASS;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

    if (!RegisterClassEx(&wcex))
    {
        exit(1);
    }

    HWND hWnd = CreateWindowEx(
     WS_EX_TOOLWINDOW,
        WIN_CLASS,
        WIN_TITLE,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
     CW_USEDEFAULT,
        500,
     100,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if (!hWnd)
    {
        exit(1);
    }

    return hWnd;
}

/*
  Main entry point
*/
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow)
{
    HWND hwnd = CreateMainWindow(hInstance);

    ShowWindow(hwnd, nCmdShow);
    SetWindowPos(hwnd, HWND_TOPMOST, -1, -1, -1, -1, SWP_NOMOVE | SWP_NOSIZE);
    UpdateWindow(hwnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}
Kevin Montrose
Setting HWND_TOPMOST doesn't work. I think I need to change the parent of my app to the desktop. I'll give it a go and report my findings.
Rob
I hack'd up some code that creates a window that resists win+D. Hopefully it can be modified to suit your needs.
Kevin Montrose
A: 

In your ABN_FULLSCREENAPP notification, you need to determine whether the window occupying the working area is the Desktop and if so, ignore the ABN_FULLSCREENAPP message.

P.S. As an alternative implementation, consider the commercial ShellAppBar component.

logicnp
This will work but only if I can find out if the Desktop is now on top, which I'm not sure about. It's a shame that the ABN_FULLSCREENAPP doesn't allow you to query the HWND of the window about go full screen, otherwise I'd be in business.
Rob
+1  A: 

use the following code and pass the window handle to the function while form load hope fully this resolves your problem

public void SetFormOnDesktop(IntPtr hwnd) {

IntPtr hwndf = hwnd;
IntPtr hwndParent = FindWindow("ProgMan", null);
SetParent(hwndf, hwndParent);

}

JKS
Works a treat! Thanks.
Rob