DwmExtendFrameIntoClientArea在Windows 10上的奇怪行为

时间:2015-12-22 11:21:40

标签: winapi windows-10 dwm

我在Windows 10上使用DwmExtendFrameIntoClientArea扩展窗口框架时遇到一些问题。下面的图片显示了我得到的行为:

enter image description here

白色标题栏颜色从顶部延伸,而从侧面和底部延伸,它延伸了窗口的彩色边缘。

如果我将边距全部设置为-1以将框架一直延伸,则窗口将填充白色并完全失去其彩色边缘:

enter image description here

这个结果非常不一致,我希望在窗口的所有侧面都可以扩展白色,类似于Windows 8中彩色框架的扩展方式,或者在Windows 7和Vista中扩展了玻璃。

我尝试过在线搜索,但我找不到任何类似的问题。

以下是我正在使用的代码:

#include <windows.h>
#include <dwmapi.h>
#include <stdio.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int main(int argc, char **argv)
{

    HINSTANCE hInstance = GetModuleHandle(NULL);
    MSG  msg;    
    HWND hwnd;
    WNDCLASSW wc;
    int message;

    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.lpszClassName = L"Window";
    wc.hInstance     = hInstance;
    wc.hbrBackground = GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpfnWndProc   = WndProc;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClassW(&wc);
    hwnd = CreateWindowW(wc.lpszClassName, L"Window",
                         WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                         100, 100, 350, 250, NULL, NULL, hInstance, NULL);  

    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);

    while(1) {
        message = GetMessageW(&msg, NULL, 0, 0);
        if(message == -1)
        {
            char x[100];
            FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 
                          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), x, 100, NULL);
            puts(x);
            abort();
        }
        else if(message == 0) break;

        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }

    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg) 
    {
        case WM_ACTIVATE:
        {
            MARGINS m = {50, 50, 50, 50};
            HRESULT hr = DwmExtendFrameIntoClientArea(hwnd, &m);
            if(!SUCCEEDED(hr))
            {
                char x[100];
                FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 
                              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), x, 100, NULL);
                puts(x);
                abort();
            }
            break;
        }
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;      
    }

    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

我做错了什么或者这只是Windows 10的一个问题?在此先感谢您的帮助!

编辑:我发布的代码与Windows 10上的Aero Lite和高对比度主题完美配合,但与默认的Windows 10主题无关。

2 个答案:

答案 0 :(得分:1)

当框架已扩展到客户区域时,您需要确保客户区绘制程序在 glass 所在的任何位置绘制纯黑色

来自MSDN

  

确保扩展帧可见的最简单方法是将整个客户端区域绘制为黑色。要完成此操作,请将WNDCLASSWNDCLASSEX结构的 hbrBackground 成员初始化为BLACK_BRUSH库存的句柄。下图显示了前面显示的相同标准框架(左)和扩展框架(右)。但是,这次 hbrBackground 设置为从GetStockObject函数获取的BLACK_BRUSH句柄。

     

enter image description here

编辑:我尝试尽可能地重现您的临时程序:

program ScratchProgram;

uses
  Windows,
  Messages,
  DwmApi,
  UxTheme;

{ Window Procedure }
function WndProc(hWnd: HWND; uiMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
    m: TMargins;
begin
    case uiMsg of
    WM_ACTIVATE:
        begin
            m.cxLeftWidth := 50;
            m.cxRightWidth := 50;
            m.cyTopHeight := 50;
            m.cyBottomHeight := 50;
            DwmExtendFrameIntoClientArea(hWnd, m);
        end;
    WM_DESTROY:
        begin
            PostQuitMessage(0);
            Result := 0;
            Exit;
        end;
    end;

    Result := DefWindowProc(hWnd, uiMsg, wParam, lParam);
end;

function WinMain(hInstance: HINST; hPrevInstance: HINST; lpCmdLine: PChar; nShowCmd: Integer): Integer; stdcall;
var
    wc: WNDCLASS;
    msg: TMSG;
    hWindow: HWND;
    instance: HINST;
begin
    instance := GetModuleHandle(nil);

    wc.style := CS_HREDRAW or CS_VREDRAW;
    wc.cbClsExtra := 0;
    wc.cbWndExtra := 0;
    wc.lpszClassName := 'Window';
    wc.hInstance := instance;
    wc.hbrBackground := GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName := nil;
    wc.lpfnWndProc := @WndProc;
    wc.hCursor := LoadCursor(0, IDC_ARROW);
    wc.hIcon := LoadIcon(0, IDI_APPLICATION);

    RegisterClass(wc);

    hWindow := CreateWindow(
            wc.lpszClassName,                  // Class Name
            'Window',                          // Title
            WS_OVERLAPPEDWINDOW or WS_VISIBLE, // Style
            100, 100,                          // Position
            350, 250,                          // Size
            0,                                 // Parent
            0,                                 // No menu
            instance,                          // Instance
            nil);                              // No special parameters

    ShowWindow(hWindow, SW_SHOW);

    while (GetMessage(msg, 0, 0, 0)) do
    begin
        TranslateMessage(msg);
        DispatchMessage(msg);
    end;

    Result := 0;
end;

begin
    WinMain(hInstance, hPrevInst, CmdLine, CmdShow);
end.

它对我有用:

enter image description here

无论问题是什么,代码在概念上看起来都不对。

也许调用约定,或者你不期望它的失败(例如RegisterClass,或者对传递给GetModuleHandle的实例句柄使用WinMain,或者调用{即使表单被停用,也会{1}}。

答案 1 :(得分:0)

您得到的结果按预期工作。有点奇怪。让我解释一下。

Windows 10使用带有单个像素蓝色边框的主题。标题栏为白色。您正在执行的操作是同时扩展标题栏和边框。因此1像素边框以及标题栏变得更大。仅仅是Windows 10主题的边框实际上是窗口框架的一部分,而不是某些魔术边框(总是一个像素)。

在Windows 7中,包括标题栏和像素的窗口框架实质上是一块完整的“玻璃”。

借助于一个名为Glass8的程序,该程序在Windows 10中恢复了Windows Aero,我得到了以下结果。 (该窗口位于灰色背景的前面。)

Aero Glass Demonstration