我们的3D应用程序窗口需要覆盖整个用户桌面(不可调整大小,不是最大化,而不是全屏,如电子游戏中所见,只是一个窗口右上角的X,标题栏和状态栏。
为实现这一目标,我们使用了以下代码:
void
CTheApp::SetFullScreenMode()
{
HWND hwnd = getHandle();
long style = ::GetWindowLong(hwnd, GWL_STYLE);
style &= ~(WS_MAXIMIZEBOX|WS_MINIMIZEBOX|WS_THICKFRAME);
::SetWindowLong(hwnd, GWL_STYLE, style);
// get screen dimensions
int width = ::GetSystemMetrics(SM_CXSCREEN);
int height = ::GetSystemMetrics(SM_CYSCREEN);
::MoveWindow(hwnd, 0, 0, width, height, TRUE);
}
它满足了我们的需求......直到Windows 10到来。
对于Windows 10,窗口没有覆盖左侧,右侧和底部的小间隙。 (更准确地说:左边9个像素,右边9个像素,底部9个像素。)
似乎Windows 10将此透明样式添加到非最大化窗口的边框。
我怎样才能使窗口在Windows 10的整个屏幕上正确显示(不留明显空隙),同时保持该功能对以前版本的Windows(Windows 7 - Windows 8.1)有效?是否有一种干净的方法将此“透明度”设置为零?
我考虑过将其破解并将每个尺寸扩大9个像素,但这可能会在用户设置另一个主题时出现问题(例如高对比度),或者当应用在多个监视器上使用多个窗口时。
答案 0 :(得分:2)
我找到了两种方法来实现这一目标。
DwmGetWindowAttribute
函数使用这种方法,我们MoveWindow
两次。我们第一次移动它时,将定位窗口并计算其所有尺寸信息。这将使我们能够获得其维度的两个方面。第二次,我们将考虑“阴影”边框。为此,我们需要ShowWindow( SW_SHOW );
之前MoveWindow
。
void MyCFrameWndMain::applyWindowSizeAndShow()
{
ShowWindow( SW_SHOW );
int targetWidth = ::GetSystemMetrics( SM_CXSCREEN );
int targetHeight = ::GetSystemMetrics( SM_CYSCREEN );
MoveWindow( 0, 0, targetWidth, targetHeight, TRUE );
RECT decoratedRect;
// This gets the rectangle "with the decoration":
GetWindowRect( &decoratedRect );
RECT leanRECT;
// This gets the rectangle "without the decoration":
::DwmGetWindowAttribute( m_hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, &leanRECT, sizeof( leanRECT ) );
int leftDecoration = leanRECT.left - decoratedRect.left;
int rightDecoration = decoratedRect.right - leanRECT.right;
int topDecoration = leanRECT.top - decoratedRect.top;
int bottomDecoration = decoratedRect.bottom - leanRECT.bottom;
// Apparently, the "rectangle without the decoration" still has a 1 pixel border on the sides and
// at the bottom, so we use the GetSystemMetrics to figure out the size of that border, and
// correct the size.
int xBorder = ::GetSystemMetrics( SM_CXBORDER );
int yBorder = ::GetSystemMetrics( SM_CYBORDER );
MoveWindow(
0 - leftDecoration - xBorder
, 0 - topDecoration - yBorder
, targetWidth + leftDecoration + rightDecoration + 2*xBorder
, targetHeight + topDecoration + bottomDecoration + 2*yBorder
, TRUE );
}
这种方法似乎比其他方法更好。
WM_NCCALCSIZE
消息使用此方法,其想法是在显示之前MoveWindow
。
void MyCFrameWndMain::applyWindowSizeAndShow()
{
int targetWidth = ::GetSystemMetrics( SM_CXSCREEN );
int targetHeight = ::GetSystemMetrics( SM_CYSCREEN );
MoveWindow( 0, 0, targetWidth, targetHeight, TRUE );
ShowWindow( SW_SHOW );
}
,然后处理WM_NCCALCSIZE
消息:
LRESULT MyCFrameWndMain::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
// ...
case WM_NCCALCSIZE:
{ // https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-nccalcsize?redirectedfrom=MSDN
int titleBarHeight = ::GetSystemMetrics( SM_CYCAPTION );
if ( wParam == TRUE )
{
NCCALCSIZE_PARAMS* params = reinterpret_cast<NCCALCSIZE_PARAMS*>( lParam );
params->rgrc[0].top = titleBarHeight;
return WVR_REDRAW;
}
else //if ( wParam == FALSE )
{
RECT* rect = reinterpret_cast<RECT*>( lParam );
rect->top = titleBarHeight;
return 0;
}
}
break;
// ...
}
}
使用此方法发现的缺点:
如果我找不到第一种方法,那么即使有很多问题,第二种方法也可以很好地满足我们的需求。
我已经使用了这些答案(在其他资源中):
答案 1 :(得分:1)
这由Desktop Window Manager处理,可以覆盖。主要步骤是WM_NCCALCSIZE(窗口消息,非客户端),您覆盖它以返回0,0