DwmExtendFrameIntoClientArea strange behaviour on Windows 10

六眼飞鱼酱① 提交于 2019-12-04 23:04:52

问题


I'm having some trouble extending the window frames using DwmExtendFrameIntoClientArea on Windows 10. The images below show the behaviour I'm getting:

The white titlebar colour is extended from the top, while from the sides and the bottom it extends the coloured edge of the window.

If I set the margins all to -1 to extend the frames all the way, the window is filled with white and loses its coloured edge altogether:

This result is very inconsistent, I was expecting the white colour to be extended on all sides of the window, similar to the way the coloured frame is extended in Windows 8, or the glass is extended in Windows 7 and Vista.

I've tried searching online, but I haven't been able to find any similar issues.

Here is the code I'm using:

#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);
}

Am I doing something wrong or is this just an issue with Windows 10? Thanks in advance for any help!

Edit: The code I posted works perfectly with both Aero Lite and the high contrast themes on Windows 10, but not with the default Windows 10 theme.


回答1:


When the frame has been extended into the client area, you need to make sure that your client area paint procedure draws pure black anywhere the glass should be.

From MSDN:

The easiest way to ensure that the extended frames are visible is to paint the entire client region black. To accomplish this, initialize the hbrBackground member of your WNDCLASS or WNDCLASSEX structure to the handle of the stock BLACK_BRUSH. The following image shows the same standard frame (left) and extended frame (right) shown previously. This time, however, hbrBackground is set to the BLACK_BRUSH handle obtained from the GetStockObject function.

Edit: I tried to reproduce your scratch program as closely as possible:

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.

And it works for me:

Whatever the problem is, the code doesn't look conceptually wrong.

Perhaps calling conventions, or a failure where you don't expect it (RegisterClass for example, or the use of GetModuleHandle over the instance handle passed to WinMain, or calling DwmExtendFrameIntoClientArea even when the form is being deactivated).




回答2:


The result you are getting is working as intended. It's just a bit weird. Let me explain.

Windows 10 uses a theme with a single pixel blue border. The titlebar is white. What you are doing with this is extending both the titlebar and the borders. So the 1 pixel borders become a lot bigger as well as the titlebar. It's just that Windows 10's theme's borders are actually a part of the window frame and not some magic border that's always a single pixel.

In Windows 7, the Window frame including the titlebar and the pixel was essentially a complete piece of "glass".

With the help of a program called Glass8, which restores Windows Aero in Windows 10, I was able to get the following result. (The window is in front of a gray background.)



来源:https://stackoverflow.com/questions/34414751/dwmextendframeintoclientarea-strange-behaviour-on-windows-10

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!