Win32(全屏)无边框窗口重叠任务栏

7
我想创建一个无边框的窗口,可以在全屏时覆盖任务栏(不使用ChangeDisplaySettings(&settings, CDS_FULLSCREEN)),但我无法弄清如何实现。我已经尝试了几乎所有可能的CreateWindowEx样式组合,但都没有成功。
它的目的是在OpenGL/DirectX中以窗口化的无边框应用程序进行渲染,同时允许Alt+Tab切换,同时在后台继续渲染。许多游戏(如魔兽世界和Dota2)以及应用程序(如Windows 7任务管理器)都使用此功能(窗口化全屏选项)。Windows 8没有这种行为。
任务管理器未聚焦: 任务管理器聚焦: 这是一些最小化的代码,我用它来轻松测试一些想法,但没有一个真正做到了。它只会创建一个大小为屏幕宽度-20和屏幕高度-20的无边框窗口。
#include <windows.h>

static bool quit = false;

static LRESULT CALLBACK message_handler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
    switch(umsg)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        case WM_CLOSE:
            quit = true;
        break;
    }

    return DefWindowProc(hwnd, umsg, wparam, lparam);
}

int main()
{
    WNDCLASSEX wc;
    HMODULE hInstance;
    HWND hwnd;
    MSG msg;

    ZeroMemory(&msg, sizeof(MSG));
    hInstance = GetModuleHandle(NULL);

    wc.style            = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.lpfnWndProc      = message_handler;
    wc.cbClsExtra       = 0;
    wc.cbWndExtra       = 0;
    wc.hInstance        = hInstance;
    wc.hIcon            = LoadIcon(NULL, IDI_WINLOGO);
    wc.hIconSm          = wc.hIcon;
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH)COLOR_WINDOWFRAME;
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = "test";
    wc.cbSize           = (unsigned int)sizeof(WNDCLASSEX);

    RegisterClassEx(&wc);

    hwnd = CreateWindowEx(WS_EX_APPWINDOW, "test", "test", WS_OVERLAPPED|WS_POPUP, 10, 10, (int)GetSystemMetrics(SM_CXSCREEN)-20, (int)GetSystemMetrics(SM_CYSCREEN)-20, NULL, NULL, hInstance, NULL);
    //hwnd = CreateWindowEx(WS_EX_APPWINDOW, "test", "test", WS_OVERLAPPED|WS_POPUP, 0, 0, (int)GetSystemMetrics(SM_CXSCREEN), (int)GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL);

    ShowWindow(hwnd, SW_SHOW);
    SetForegroundWindow(hwnd);
    SetFocus(hwnd);

    while (!quit)
    {
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return 0;
}

使用

CreateWindowEx(WS_EX_APPWINDOW, "test", "test", WS_OVERLAPPED|WS_POPUP, 0, 0, (int)GetSystemMetrics(SM_CXSCREEN), (int)GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL);

当opengl在任务栏上渲染时,它会重叠到任务栏上,但是会出现一些奇怪的行为(例如屏幕闪烁/闪烁,就像视频模式更改时一样)。某个类似于用于渲染和其他内容的跨平台窗口库的论坛上遇到了相同的效果。该主题中还有人发布了一个视频(请注意,音乐很响),展示了我正在尝试实现的内容。

我已经下载了那个开源库并尝试找出它的特殊之处,但我找不到任何特别的地方。

在Windows8上使用g++ (Built by MinGW-builds project) 4.8.0 20121225 (experimental)


我看到了你试图编辑我的答案,我很感激你的尝试。通常展示最终解决方案的方法是将其编辑到你的问题中。 - Mark Ransom
@MarkRansom 我明白了,谢谢你告诉我这个。不过,在我完成所有这些操作之前,新答案已经出现了。在决定使用哪一个之前,我将尝试一下 SetWindowPlacement 的想法。 - Edward A
如果你觉得需要更改你选择的答案,我不会个人对待。 - Mark Ransom
2个回答

9
Raymond Chen通过使用SetWindowLong(Ptr)改变窗口样式,使用SetWindowPlacement调整窗口大小,并使用SetWindowPos确保框架重新绘制而相对简单地解释了如何在全屏模式下切换。
任务栏会检测窗口尝试进入全屏模式并自动退出。

关于任务栏行为的有趣部分,我认为您需要处于最顶层才能置于其上方。 - Mark Ransom

4

使用SetWindowPos函数将窗口设置为最顶层。当您收到失去焦点的消息时,将其设置为非最顶层,以便您切换到的其他窗口可以出现。


1
马克,你能评论一下哪个消息会表明它失去了焦点吗?谢谢!(我也遇到了同样的问题。) - bodacydo
1
@bodacydo 尝试使用 WM_KILLFOCUS - Mark Ransom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接