36

我有一个窗户,我SetWindowPos(window, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_FRAMECHANGED);

它覆盖了整个屏幕,好的,但也需要一段时间(0.5 秒)才能覆盖任务栏。

有没有办法立即通过任务栏?我发现设置HWND_TOPMOST会立即执行此操作,但它始终高于所有其他窗口,即使我切换应用程序 - 这是我不想要的。此外,如果我先隐藏窗口然后显示它,它会以某种方式强制窗口重新绘制并立即覆盖任务栏,但它会闪烁(因为隐藏)。还有其他方法吗?

4

6 回答 6

49

编辑 2。甚至还有一种更好的全屏方式,铬方式,来源取自这里:

http://src.chromium.org/viewvc/chrome/trunk/src/ui/views/win/fullscreen_handler.cc?revision=HEAD&view=markup

void FullscreenHandler::SetFullscreenImpl(bool fullscreen, bool for_metro) {
  ScopedFullscreenVisibility visibility(hwnd_);

  // Save current window state if not already fullscreen.
  if (!fullscreen_) {
    // Save current window information.  We force the window into restored mode
    // before going fullscreen because Windows doesn't seem to hide the
    // taskbar if the window is in the maximized state.
    saved_window_info_.maximized = !!::IsZoomed(hwnd_);
    if (saved_window_info_.maximized)
      ::SendMessage(hwnd_, WM_SYSCOMMAND, SC_RESTORE, 0);
    saved_window_info_.style = GetWindowLong(hwnd_, GWL_STYLE);
    saved_window_info_.ex_style = GetWindowLong(hwnd_, GWL_EXSTYLE);
    GetWindowRect(hwnd_, &saved_window_info_.window_rect);
  }

  fullscreen_ = fullscreen;

  if (fullscreen_) {
    // Set new window style and size.
    SetWindowLong(hwnd_, GWL_STYLE,
                  saved_window_info_.style & ~(WS_CAPTION | WS_THICKFRAME));
    SetWindowLong(hwnd_, GWL_EXSTYLE,
                  saved_window_info_.ex_style & ~(WS_EX_DLGMODALFRAME |
                  WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));

    // On expand, if we're given a window_rect, grow to it, otherwise do
    // not resize.
    if (!for_metro) {
      MONITORINFO monitor_info;
      monitor_info.cbSize = sizeof(monitor_info);
      GetMonitorInfo(MonitorFromWindow(hwnd_, MONITOR_DEFAULTTONEAREST),
                     &monitor_info);
      gfx::Rect window_rect(monitor_info.rcMonitor);
      SetWindowPos(hwnd_, NULL, window_rect.x(), window_rect.y(),
                   window_rect.width(), window_rect.height(),
                   SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
    }
  } else {
    // Reset original window style and size.  The multiple window size/moves
    // here are ugly, but if SetWindowPos() doesn't redraw, the taskbar won't be
    // repainted.  Better-looking methods welcome.
    SetWindowLong(hwnd_, GWL_STYLE, saved_window_info_.style);
    SetWindowLong(hwnd_, GWL_EXSTYLE, saved_window_info_.ex_style);

    if (!for_metro) {
      // On restore, resize to the previous saved rect size.
      gfx::Rect new_rect(saved_window_info_.window_rect);
      SetWindowPos(hwnd_, NULL, new_rect.x(), new_rect.y(),
                   new_rect.width(), new_rect.height(),
                   SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
    }
    if (saved_window_info_.maximized)
      ::SendMessage(hwnd_, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
  }
}

编辑. 正如 BrendanMcK 在对此答案的评论中指出的那样,创建一个全屏窗口可能会更好,请参阅此链接:http: //blogs.msdn.com/b/oldnewthing/archive/2005/05/05/414910.aspx(“如何用全屏窗口覆盖任务栏?”)

使用上面链接的新代码将是:

HWND CreateFullscreenWindow(HWND hwnd)
{
 HMONITOR hmon = MonitorFromWindow(hwnd,
                                   MONITOR_DEFAULTTONEAREST);
 MONITORINFO mi = { sizeof(mi) };
 if (!GetMonitorInfo(hmon, &mi)) return NULL;
 return CreateWindow(TEXT("static"),
       TEXT("something interesting might go here"),
       WS_POPUP | WS_VISIBLE,
       mi.rcMonitor.left,
       mi.rcMonitor.top,
       mi.rcMonitor.right - mi.rcMonitor.left,
       mi.rcMonitor.bottom - mi.rcMonitor.top,
       hwnd, NULL, g_hinst, 0);
}

下面的旧答案 - 不要使用它,仅用于记录如何不这样做。

您必须隐藏任务栏和菜单栏才能立即全屏查看。

这是代码(使用 WTL),调用 SetFullScreen(true) 进入全屏模式:

template <class T, bool t_bHasSip = true>
class CFullScreenFrame
{
public:
    bool m_fullscreen;
    LONG m_windowstyles;
    WINDOWPLACEMENT m_windowplacement;

    CFullScreenFrame() 
        :
        m_fullscreen(false),
        m_windowstyles(0)
    { }

    void SetFullScreen(bool fullscreen)
    {
        ShowTaskBar(!fullscreen);

        T* pT = static_cast<T*>(this);

        if (fullscreen) {
            if (!m_fullscreen) {
                m_windowstyles = pT->GetWindowLongW(GWL_STYLE);
                pT->GetWindowPlacement(&m_windowplacement);
            }

        }

        // SM_CXSCREEN gives primary monitor, for multiple monitors use SM_CXVIRTUALSCREEN.
        RECT fullrect = { 0 };              
        SetRect(&fullrect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));

        WINDOWPLACEMENT newplacement = m_windowplacement;
        newplacement.showCmd = SW_SHOWNORMAL;
        newplacement.rcNormalPosition = fullrect;

        if (fullscreen) {
            pT->SetWindowPlacement(&newplacement);
            pT->SetWindowLongW(GWL_STYLE,  WS_VISIBLE);
            pT->UpdateWindow();
        } else {
            if (m_fullscreen) {
                pT->SetWindowPlacement(&m_windowplacement);
                pT->SetWindowLongW(GWL_STYLE, m_windowstyles);
                pT->UpdateWindow();
            }
        }

        m_fullscreen = fullscreen;
    }

    void ShowTaskBar(bool show)
    {
        HWND taskbar = FindWindow(_T("Shell_TrayWnd"), NULL);
        HWND start = FindWindow(_T("Button"), NULL);

        if (taskbar != NULL) {
            ShowWindow(taskbar, show ? SW_SHOW : SW_HIDE);
            UpdateWindow(taskbar);
        }
        if (start != NULL) { 
            // Vista
            ShowWindow(start, show ? SW_SHOW : SW_HIDE);
            UpdateWindow(start);
        }       
    }
};

您还必须向 WM_CLOSE 消息添加一些代码:

case WM_CLOSE:
    ShowTaskBar(true);

此解决方案有一个警告,如果您的应用程序崩溃或被任务管理器杀死,那么用户将永久丢失其系统上的任务栏!(除非他再次运行您的应用程序,进入全屏并退出,否则他将再次看到任务栏)。

在我之前的回答中,我指出了“atlwince.h”,但该功能仅适用于 Windows CE,我在上面粘贴的那个适用于 XP、Vista 和 7。

于 2011-03-14T14:10:14.343 回答
19

是的,HWND_TOPMOST为我做。这是使全屏对我来说很好(并且快速)工作的一段代码:


bool enterFullscreen(HWND hwnd, int fullscreenWidth, int fullscreenHeight, int colourBits, int refreshRate) {
    DEVMODE fullscreenSettings;
    bool isChangeSuccessful;
    RECT windowBoundary;

    EnumDisplaySettings(NULL, 0, &fullscreenSettings);
    fullscreenSettings.dmPelsWidth        = fullscreenWidth;
    fullscreenSettings.dmPelsHeight       = fullscreenHeight;
    fullscreenSettings.dmBitsPerPel       = colourBits;
    fullscreenSettings.dmDisplayFrequency = refreshRate;
    fullscreenSettings.dmFields           = DM_PELSWIDTH |
                                            DM_PELSHEIGHT |
                                            DM_BITSPERPEL |
                                            DM_DISPLAYFREQUENCY;

    SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_TOPMOST);
    SetWindowLongPtr(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
    SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fullscreenWidth, fullscreenHeight, SWP_SHOWWINDOW);
    isChangeSuccessful = ChangeDisplaySettings(&fullscreenSettings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL;
    ShowWindow(hwnd, SW_MAXIMIZE);

    return isChangeSuccessful;
}

请注意,如果您告诉它错误的设置,这将改变分辨率。mainWindow这是我通常想要的,但如果你不喜欢这样,你可以通过使用 (where is from something like CreateWindow()or )找出你的分辨率CreateWindowEx()


windowHDC = GetDC(mainWindow);
fullscreenWidth  = GetDeviceCaps(windowHDC, DESKTOPHORZRES);
fullscreenHeight = GetDeviceCaps(windowHDC, DESKTOPVERTRES);
colourBits       = GetDeviceCaps(windowHDC, BITSPIXEL);
refreshRate      = GetDeviceCaps(windowHDC, VREFRESH);

当您想退出全屏时,您可以执行以下操作:


bool exitFullscreen(HWND hwnd, int windowX, int windowY, int windowedWidth, int windowedHeight, int windowedPaddingX, int windowedPaddingY) {
    bool isChangeSuccessful;

    SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_LEFT);
    SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
    isChangeSuccessful = ChangeDisplaySettings(NULL, CDS_RESET) == DISP_CHANGE_SUCCESSFUL;
    SetWindowPos(hwnd, HWND_NOTOPMOST, windowX, windowY, windowedWidth + windowedPaddingX, windowedHeight + windowedPaddingY, SWP_SHOWWINDOW);
    ShowWindow(hwnd, SW_RESTORE);

    return isChangeSuccessful;
}

我将代码设置为使用热键在全屏模式和窗口模式之间切换,并将窗口模式变量保持为全局变量,以便在切换到窗口模式时保持不变。

这段代码还具有运行在“独占模式”等效的优势(我使用的是 XP,并没有在较新版本的 windows 上尝试过),这意味着它会快得多。如果我在压缩代码(来自我更大的代码)中犯了任何错误,请告诉我。

于 2010-03-10T11:56:52.480 回答
10

Raymond Chen 在他的博客中描述了这样做的“正确”方法:

https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353

建议显式摆弄任务栏窗口。

于 2012-03-13T11:53:42.673 回答
2

这是 Raymond Chen 答案的最新完整链接

由于 MSDN/Microsoft 不断断开链接,我将在下面粘贴以供后代使用:


出于某种原因,人们想得太难了。如果你想创建一个覆盖任务栏的全屏窗口,只需创建一个全屏窗口,任务栏就会自动消失。不要四处寻找任务栏并戳它;让它做它的事。

与往常一样,从临时程序开始并添加以下内容:

HWND CreateFullscreenWindow(HWND hwnd)
{
 HMONITOR hmon = MonitorFromWindow(hwnd,
                                   MONITOR_DEFAULTTONEAREST);
 MONITORINFO mi = { sizeof(mi) };
 if (!GetMonitorInfo(hmon, &mi)) return NULL;
 return CreateWindow(TEXT("static"),
       TEXT("something interesting might go here"),
       WS_POPUP | WS_VISIBLE,
       mi.rcMonitor.left,
       mi.rcMonitor.top,
       mi.rcMonitor.right - mi.rcMonitor.left,
       mi.rcMonitor.bottom - mi.rcMonitor.top,
       hwnd, NULL, g_hinst, 0);
}

void OnChar(HWND hwnd, TCHAR ch, int cRepeat)
{
 if (ch == TEXT(' ')) {
  CreateFullscreenWindow(hwnd);
 }
}

HANDLE_MSG(hwnd, WM_CHAR, OnChar);

请注意,此示例程序不担心破坏该全屏窗口或阻止用户创建多个窗口。这只是一个样本。重点是看 CreateFullScreenWindow 函数是如何编写的。

我们使用MonitorFromWindow 函数来确定我们应该全屏显示哪个监视器。请注意,在多显示器系统中,这可能与任务栏所在的显示器不同。幸运的是,我们不必担心这一点。任务栏算出来了。

我见过人们寻找任务栏窗口,然后在上面执行 ShowWindow(hwndTaskbar, SW_HIDE) 。这很疯狂,原因有很多。

首先是在评估类似这样的技巧时应该始终使用的心理练习:“如果两个程序尝试了这个技巧怎么办?” 现在你有两个程序,它们都认为它们负责隐藏和显示任务栏,它们都没有相互协调。结果是一团糟。一个程序隐藏任务栏,然后另一个程序隐藏任务栏,然后第一个程序决定它已完成,因此它取消隐藏任务栏,但第二个程序尚未完成并在它认为应该隐藏时获得一个可见的任务栏。事情只会从那里走下坡路。

其次,如果您的程序在有机会取消隐藏任务栏之前就崩溃了怎么办?任务栏现在永久隐藏,用户必须注销并重新登录才能恢复他们的任务栏。那样不是很好。

第三,如果根本没有任务栏怎么办?在终端服务器场景中,无需资源管理器(已存档自行运行程序是很常见的。在此配置中,没有资源管理器,也没有任务栏。或者,您可能正在运行没有任务栏的未来版本的 Windows,它已被其他一些机制取代。你的程序现在会做什么?

不要对任务栏做任何这样的事情。只需创建您的全屏窗口并让任务栏自动完成它的工作。

于 2020-04-15T20:02:28.757 回答
1

我相信当它的外壳钩子告诉它一个“粗鲁的应用程序”时,任务栏会离开,这可能需要一点时间。

如果您从窗口 HWND_TOPMOST 开始并使其在 1 秒后不是最顶部怎么办?

于 2010-03-06T16:56:32.537 回答
-5
  1. 右键单击任务栏
  2. 选择属性
  3. 取消选中“将任务栏保持在其他窗口之上”的复选框。

任务栏属于用户,当您的应用程序全屏显示时,他们需要关心是否需要 1/2 秒自动隐藏。如果他们想改变这种行为,那么他们可以改变它。

如果您在嵌入式系统中工作,那么您可能有正当理由隐藏任务栏。但在这种情况下,没有理由不简单地将任务栏配置为不总是在顶部。您还可以查看SystemParametersInfo是否要更改代码中的某些设置。

于 2010-03-06T01:06:53.893 回答