2

我有一个 Windows 应用程序,它使用 AppBar API 安装为屏幕顶部的应用程序栏(类似于 Windows 任务栏本身)。这很好用,桌面大小也会相应调整,所以我的应用程序总是可见的。

但是,如果用户选择“显示桌面”(Windows+D),我的应用程序将被隐藏。有谁知道捕获“显示桌面”的方法,以便我可以确保我的应用程序保持可见(我假设 Windows 枚举所有顶级窗口并使用 ShowWindow(SW_HIDE) 隐藏它们。

4

4 回答 4

1

使用以下代码并在表单加载时将窗口句柄传递给函数。希望这可以解决您的问题。

public void SetFormOnDesktop(IntPtr hwnd)
{
    IntPtr hwndf = hwnd;
    IntPtr hwndParent = FindWindow("ProgMan", null);
    SetParent(hwndf, hwndParent);
}
于 2010-01-05T12:34:09.983 回答
0

我的印象是,将窗口设置为最顶层窗口(通过SetWindowPos和 HWND_TOPMOST 标志)会阻止桌面覆盖它。Windows+D 会最小化所有窗口,然后通过按 z 顺序提升桌面来覆盖那些无法最小化的窗口(好吧,无论如何它确实在某一点上做到了)。我相信您可以通过不将 WS_MINIMIZEBOX 传递给 CreateWindowEx 或使用 WS_EX_TOOLWINDOW 来使窗口无法最小化,尽管我不是 100% 的。

更重手的方法是使用 SetWindowsHookEx 和 KeyboardProc 挂钩全局键盘。这将对用户体验产生有害影响。


我去编写了一个非常简单的例子来说明我在说什么。以下代码创建了一个未被最小化的窗口,或者被用户点击 Windows+D 覆盖。请注意,在 Windows 7 上,桌面上的小工具仍然可以置于其上方;我真的无法解释。

#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;
}
于 2009-05-22T03:43:07.433 回答
0

在您的 ABN_FULLSCREENAPP 通知中,您需要确定占用工作区的窗口是否是桌面,如果是,则忽略 ABN_FULLSCREENAPP 消息。

PS 作为替代实现,请考虑商业ShellAppBar组件。

于 2009-07-13T05:16:20.100 回答
0

除了JKS 的答案,这里是 VB.NET 的工作代码,假设您已经将表单转换为 appbar。您需要 p/invoke 函数FindWindowSetFormOnDesktop.

'In your form
Public Sub New()
    'Stuff
    SetFormOnDesktop(Me.Handle)
    'More stuff
End Sub

'In your form or somewhere else.
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function FindWindow( _
 ByVal lpClassName As String, _
 ByVal lpWindowName As String) As IntPtr
End Function

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Shared Function SetParent(_
 ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
End Function

Public Sub SetFormOnDesktop(hwnd As IntPtr)
    Dim hwndf As IntPtr = hwnd
    Dim hwndParent As IntPtr = FindWindow("ProgMan", Nothing)
    SetParent(hwndf, hwndParent)
End Sub
于 2014-02-27T14:23:13.613 回答