DWMBlurGlass icon indicating copy to clipboard operation
DWMBlurGlass copied to clipboard

Borders of certain non-resizable Windows

Open aubymori opened this issue 1 year ago • 21 comments

Since Windows 10, the physical border width on certain non-resizable windows has been intentionally shrunk. See the below image:

Windows 10 borders

Explorer: Resizable, thick borders OldNewExplorer configuration: Non-resizable, thin borders Winver: Non-resizable, ...thick borders?

Not all non-resizable windows have thin borders for whatever reason. ~~From what I can tell, every non-resizable window that is a dialog (e.g. spawned by DialogBoxParamW) has thick borders,~~ (no, they don't) but there are more which do, so I don't know the exact parameters for it. Anyways, here is the exact same window configuration in Windows 8.1.

Windows 8.1 borders

As you can see, the borders here are all thick, despite two out of three of these windows being non-resizable.

aubymori avatar Feb 11 '24 22:02 aubymori

Something I just noticed: the appearance of all non-resizable borders are the same, no matter the width. Take a look at this:

The border colors

The Explorer window's borders match the titlebar, but both Winver and OldNewExplorer configuration have a faded color. I can't imagine this has much relevance, but it's still worth pointing out.

aubymori avatar Feb 11 '24 22:02 aubymori

So, what do you want to achieve?

Maplespe avatar Feb 12 '24 02:02 Maplespe

So, what do you want to achieve?

That's exactly what I'm wondering 😂 I don't see how this is a bug with DWMBG

Olive6841 avatar Feb 12 '24 02:02 Olive6841

So, what do you want to achieve?

Oh, sorry that I wasn't clear with that, haha. I want to achieve the borders Vista-8.1 had in 10 with DWMBG. This program has had other stuff for old themes like that added in the past, so I figured it wouldn't be out of scope for the project.

That's exactly what I'm wondering 😂 I don't see how this is a bug with DWMBG

Not a bug report, feature request. Note the "enhancement" tag.

aubymori avatar Feb 12 '24 04:02 aubymori

Check out this WindHawk mod, it works for me: https://windhawk.net/mods/force-thick-frames

NebelNidas avatar Mar 30 '24 10:03 NebelNidas

@NebelNidas I have tried but the solution you given have some bugs.

The first bug: As for windows with WS_THICKFRAME style, the cursor will become cross (resizing) when hovering the border of these windows, even if these windows are not resizable.

Before using force-thick-frames.

image

After using force-thick-frames.

image

Another bug: there are some windows which still have a thin border, even using force-thick-frames.

image

I also found out such an opinion from https://github.com/Maplespe/DWMBlurGlass/issues/248, and hope it will be useful.

A window can have a thick frame without having WS_THICKFRAME style.

Wait for better solution, and hope DWMBlurGlass can solve this problem.

Aoi-hosizora avatar Apr 03 '24 11:04 Aoi-hosizora

The Explorer window's borders match the titlebar, but both Winver and OldNewExplorer configuration have a faded color. I can't imagine this has much relevance, but it's still worth pointing out.

I have noticed all apps with ribbon don't use borders the same way like other apps, they use the title bars color, which is also the reason of the missing black border in file explorer and other ribbon apps

funn-hue avatar Apr 03 '24 11:04 funn-hue

Windows 7 calculates the difference between thick border frame and thin border frame in "CTopLevelWindow::CalculateOutsideMargins", then sets a margin using SetMargin function

We can do the same as Windows 7 but it has problems:

  1. DWMBlurGlass custom blur method doesn't have in mind the margins
  2. You can click through the borders margin

Screenshot_20240412_204452

I did a quick Windhawk mod (only tested on 21H2 LTSC) that i will leave here if someone wants to test, any help for fixing the problems is appreciated

// ==WindhawkMod==
// @id              thick-frames
// @name            DWM thick frames test
// @version         0.1
// @include         dwm.exe
// ==/WindhawkMod==

#include <uxtheme.h>
#include <windhawk_api.h>
#include <windhawk_utils.h>

bool(__thiscall* SetMargin)(struct _MARGINS*, int, int, int, int, struct _MARGINS const*);

bool __thiscall SetMargin_hook(struct _MARGINS* a1, int cxLeftWidth, int cxRightWidth, int cyTopHeight, int cyBottomHeight, struct _MARGINS const* a6) {
    return SetMargin(a1, cxLeftWidth, cxRightWidth, cyTopHeight, cyBottomHeight, a6);
}

bool(__thiscall* UpdateMarginsDependentOnStyle)(void*);
bool __thiscall UpdateMarginsDependentOnStyle_hook(void* pThis) {
    int ret = UpdateMarginsDependentOnStyle(pThis);
    struct tagRECT Rect;
    struct _MARGINS a3;
    DWORD* windowData;
    int dwStyle;
    DWORD dwExStyle;
    int v8;
    LONG v9;
    int v10;
    int v11;
    LONG right;
    int v13;
    int v14;
    LONG v15;
    LONG bottom;

    windowData = (DWORD*)*((unsigned long long*)pThis + 91);
    dwStyle = windowData[25];
    dwExStyle = windowData[26];

    // CalculateOutsideMargins from Windows 7
    Rect.left = 0;
    Rect.top = 0;
    Rect.right = 0;
    Rect.bottom = 0;
    AdjustWindowRectEx(&Rect, dwStyle | 0x40000, 0, dwExStyle);
    v8 = windowData[16];
    v9 = windowData[17];
    v10 = -Rect.left;
    v11 = -Rect.top;
    if (v8 > -Rect.left)
        v10 = windowData[16];
    a3.cxLeftWidth = v8 - v10;
    right = Rect.right;
    if (v9 > Rect.right)
        right = v9;
    v13 = v9 - right;
    v14 = windowData[18];
    a3.cxRightWidth = v13;
    v15 = windowData[19];
    if (v14 > v11)
        v11 = v14;
    a3.cyTopHeight = v14 - v11;
    bottom = Rect.bottom;
    if (v15 > Rect.bottom)
        bottom = v15;
    a3.cyBottomHeight = v15 - bottom;
    
    // Check NC size
    if (windowData[16] > 0 && windowData[17] > 0 && windowData[18] > 0 && windowData[19] > 0) {
        SetMargin((struct _MARGINS*)((char*)pThis + 628), a3.cxLeftWidth,
                  a3.cxRightWidth, a3.cyTopHeight, a3.cyBottomHeight, 0);
    }

    return ret;
}

BOOL Wh_ModInit() {
    Wh_Log(L"Init");

    HMODULE uDWM = LoadLibraryW(L"uDWM.dll");

    if (!uDWM) {
        Wh_Log(L"Failed to load uDWM.dll");
        return FALSE;
    }

    WindhawkUtils::SYMBOL_HOOK symbolHooks[] = {
        {
            {L"private: bool __cdecl CTopLevelWindow::UpdateMarginsDependentOnStyle(void)"},
            (void**)&UpdateMarginsDependentOnStyle,
            (void*)UpdateMarginsDependentOnStyle_hook,
        },
        {
            {L"bool __cdecl SetMargin(struct _MARGINS *,int,int,int,int,struct _MARGINS const *)"},
            (void**)&SetMargin,
            (void*)SetMargin_hook,
        },
    };

    if (!WindhawkUtils::HookSymbols(uDWM, symbolHooks, ARRAYSIZE(symbolHooks))) {
        Wh_Log(L"Error hooking");
        return FALSE;
    }
    return TRUE;
}

Xdmg01 avatar Apr 12 '24 20:04 Xdmg01

Windows 7 calculates the difference between thick border frame and thin border frame in "CTopLevelWindow::CalculateOutsideMargins", then sets a margin using SetMargin function

We can do the same as Windows 7 but it has problems:

1. DWMBlurGlass custom blur method doesn't have in mind the margins

2. You can click through the borders margin

Screenshot_20240412_204452

I did a quick Windhawk mod (only tested on 21H2 LTSC) that i will leave here if someone wants to test, any help for fixing the problems is appreciated

// ==WindhawkMod==
// @id              thick-frames
// @name            DWM thick frames test
// @version         0.1
// @include         dwm.exe
// ==/WindhawkMod==

#include <uxtheme.h>
#include <windhawk_api.h>
#include <windhawk_utils.h>

bool(__thiscall* SetMargin)(struct _MARGINS*, int, int, int, int, struct _MARGINS const*);

bool __thiscall SetMargin_hook(struct _MARGINS* a1, int cxLeftWidth, int cxRightWidth, int cyTopHeight, int cyBottomHeight, struct _MARGINS const* a6) {
    return SetMargin(a1, cxLeftWidth, cxRightWidth, cyTopHeight, cyBottomHeight, a6);
}

bool(__thiscall* UpdateMarginsDependentOnStyle)(void*);
bool __thiscall UpdateMarginsDependentOnStyle_hook(void* pThis) {
    int ret = UpdateMarginsDependentOnStyle(pThis);
    struct tagRECT Rect;
    struct _MARGINS a3;
    DWORD* windowData;
    int dwStyle;
    DWORD dwExStyle;
    int v8;
    LONG v9;
    int v10;
    int v11;
    LONG right;
    int v13;
    int v14;
    LONG v15;
    LONG bottom;

    windowData = (DWORD*)*((unsigned long long*)pThis + 91);
    dwStyle = windowData[25];
    dwExStyle = windowData[26];

    // CalculateOutsideMargins from Windows 7
    Rect.left = 0;
    Rect.top = 0;
    Rect.right = 0;
    Rect.bottom = 0;
    AdjustWindowRectEx(&Rect, dwStyle | 0x40000, 0, dwExStyle);
    v8 = windowData[16];
    v9 = windowData[17];
    v10 = -Rect.left;
    v11 = -Rect.top;
    if (v8 > -Rect.left)
        v10 = windowData[16];
    a3.cxLeftWidth = v8 - v10;
    right = Rect.right;
    if (v9 > Rect.right)
        right = v9;
    v13 = v9 - right;
    v14 = windowData[18];
    a3.cxRightWidth = v13;
    v15 = windowData[19];
    if (v14 > v11)
        v11 = v14;
    a3.cyTopHeight = v14 - v11;
    bottom = Rect.bottom;
    if (v15 > Rect.bottom)
        bottom = v15;
    a3.cyBottomHeight = v15 - bottom;
    
    // Check NC size
    if (windowData[16] > 0 && windowData[17] > 0 && windowData[18] > 0 && windowData[19] > 0) {
        SetMargin((struct _MARGINS*)((char*)pThis + 628), a3.cxLeftWidth,
                  a3.cxRightWidth, a3.cyTopHeight, a3.cyBottomHeight, 0);
    }

    return ret;
}

BOOL Wh_ModInit() {
    Wh_Log(L"Init");

    HMODULE uDWM = LoadLibraryW(L"uDWM.dll");

    if (!uDWM) {
        Wh_Log(L"Failed to load uDWM.dll");
        return FALSE;
    }

    WindhawkUtils::SYMBOL_HOOK symbolHooks[] = {
        {
            {L"private: bool __cdecl CTopLevelWindow::UpdateMarginsDependentOnStyle(void)"},
            (void**)&UpdateMarginsDependentOnStyle,
            (void*)UpdateMarginsDependentOnStyle_hook,
        },
        {
            {L"bool __cdecl SetMargin(struct _MARGINS *,int,int,int,int,struct _MARGINS const *)"},
            (void**)&SetMargin,
            (void*)SetMargin_hook,
        },
    };

    if (!WindhawkUtils::HookSymbols(uDWM, symbolHooks, ARRAYSIZE(symbolHooks))) {
        Wh_Log(L"Error hooking");
        return FALSE;
    }
    return TRUE;
}

I haven't looked into it exactly, but Windows 10 DWM and UxTheme (XP-7 basic theme window frames) seem to share the same conditions for thin-framed windows. I don't know what these conditions are, but it's true that at least programs running under compatibility mode tend to (always?) use thin frames, even if they're resizable.

kawapure avatar Apr 13 '24 00:04 kawapure

@Xdmg01 I'm a beginner on Windhawk, so maybe I misuse your code. I have tested your mod on Windows 10 22H2 but it still don't work.

image

Aoi-hosizora avatar Apr 13 '24 02:04 Aoi-hosizora

@Xdmg01 I'm a beginner on Windhawk, so maybe I misuse your code. I have tested your mod on Windows 10 22H2 but it still don't work.

image

You need to set up Windhawk to allow DWM injection. In the advanced settings, there should be a special placeholder setting "<critical_system_processes>" in the process exclusion list. You must remove this and ensure that the setting "Load mods into critical system processes" (doesn't even seem to be translated into Japanese lol) is set to an option to allow it. Then it should be able to inject into DWM.

By the way, if a DWM mod is incompatible, you can brick your system and need to use another OS or boot into a Windows installer to fix it. Remove the compiled mod DLL at C:\ProgramData\Windhawk\Engine\Mods\64 and you should be alright.

kawapure avatar Apr 13 '24 03:04 kawapure

I should mention the cases of this occurring:

This behaviour has been present since Windows Vista. However, back then, it was limited to the basic theme (UxTheme), with Aero extending the frames beyond their "real" size to compensate. As of Windows 10, DWM also does this.

This occurs in any application that is not built with a subsystem version of at least 6.00. These applications are just not allowed to access the border padding metrics at all, including UxTheme itself, which is responsible for drawing window frames. Basically, any program that supports XP gets these as a compatibility hack.

See also: https://web.archive.org/web/20110910065719/http://objectmix.com/clipper/749482-getsystemmetrics-sm_cxpaddedborder.html

kawapure avatar Apr 13 '24 18:04 kawapure

I should mention the cases of this occurring:

This behaviour has been present since Windows Vista. However, back then, it was limited to the basic theme (UxTheme), with Aero extending the frames beyond their "real" size to compensate. As of Windows 10, DWM also does this.

This occurs in any application that is not built with a subsystem version of at least 6.00. These applications are just not allowed to access the border padding metrics at all, including UxTheme itself, which is responsible for drawing window frames. Basically, any program that supports XP gets these as a compatibility hack.

See also: https://web.archive.org/web/20110910065719/http://objectmix.com/clipper/749482-getsystemmetrics-sm_cxpaddedborder.html

Also, seemingly any application run in compatibility mode gets thin borders on every window, including resizable ones. However, using the Application Verifier utility's HighVersionLie removes that effect and makes borders act as if compatibility mode was not enabled.

aubymori avatar Apr 13 '24 18:04 aubymori

Oh, also, dialogness, like I mentioned in the OP, is not relevant at all. I was mistaken.

aubymori avatar Apr 13 '24 18:04 aubymori

I should mention the cases of this occurring: This behaviour has been present since Windows Vista. However, back then, it was limited to the basic theme (UxTheme), with Aero extending the frames beyond their "real" size to compensate. As of Windows 10, DWM also does this. This occurs in any application that is not built with a subsystem version of at least 6.00. These applications are just not allowed to access the border padding metrics at all, including UxTheme itself, which is responsible for drawing window frames. Basically, any program that supports XP gets these as a compatibility hack. See also: https://web.archive.org/web/20110910065719/http://objectmix.com/clipper/749482-getsystemmetrics-sm_cxpaddedborder.html

Also, seemingly any application run in compatibility mode gets thin borders on every window, including resizable ones. However, using the Application Verifier utility's HighVersionLie removes that effect and makes borders act as if compatibility mode was not enabled.

The resizable "thin borders" when using compatibility mode aren't the same as non resizable thin borders, they are 1px wider Also this happens with basic frames so Dwm has probably nothing to do with it

Xdmg01 avatar Apr 14 '24 18:04 Xdmg01

I should mention the cases of this occurring: This behaviour has been present since Windows Vista. However, back then, it was limited to the basic theme (UxTheme), with Aero extending the frames beyond their "real" size to compensate. As of Windows 10, DWM also does this. This occurs in any application that is not built with a subsystem version of at least 6.00. These applications are just not allowed to access the border padding metrics at all, including UxTheme itself, which is responsible for drawing window frames. Basically, any program that supports XP gets these as a compatibility hack. See also: https://web.archive.org/web/20110910065719/http://objectmix.com/clipper/749482-getsystemmetrics-sm_cxpaddedborder.html

Also, seemingly any application run in compatibility mode gets thin borders on every window, including resizable ones. However, using the Application Verifier utility's HighVersionLie removes that effect and makes borders act as if compatibility mode was not enabled.

The resizable "thin borders" when using compatibility mode aren't the same as non resizable thin borders, they are 1px wider Also this happens with basic frames so Dwm has probably nothing to do with it

DWM has everything to do with it. This has always happened on basic frames, just that Windows Vista/7/8.x DWM ignored the border size and always used thick frames. There is even an API specifically to get the DWM window's rect including the fake DWM border. (DwmGetWindowAttribute with DWMWA_EXTENDED_FRAME_BOUNDS attribute)

aubymori avatar Apr 14 '24 19:04 aubymori

I also noticed that with the modcode above, extended frame dialog windows do not blink (i.e. flicker between active and inactive titlebar colors) when clicked outside the active area, instead staying on the same active titlebar style. This bug does not affect the other dialogs whose margins were not changed.

CatmanFan avatar Apr 19 '24 23:04 CatmanFan

Is there any way to achieve this without windhawk and compatbility mode? The thin borders look ugly and bug me.

ideapc avatar May 17 '24 05:05 ideapc

Windows 7 calculates the difference between thick border frame and thin border frame in "CTopLevelWindow::CalculateOutsideMargins", then sets a margin using SetMargin function

We can do the same as Windows 7 but it has problems:

1. DWMBlurGlass custom blur method doesn't have in mind the margins

2. You can click through the borders margin

Screenshot_20240412_204452

I did a quick Windhawk mod (only tested on 21H2 LTSC) that i will leave here if someone wants to test, any help for fixing the problems is appreciated

// ==WindhawkMod==
// @id              thick-frames
// @name            DWM thick frames test
// @version         0.1
// @include         dwm.exe
// ==/WindhawkMod==

#include <uxtheme.h>
#include <windhawk_api.h>
#include <windhawk_utils.h>

bool(__thiscall* SetMargin)(struct _MARGINS*, int, int, int, int, struct _MARGINS const*);

bool __thiscall SetMargin_hook(struct _MARGINS* a1, int cxLeftWidth, int cxRightWidth, int cyTopHeight, int cyBottomHeight, struct _MARGINS const* a6) {
    return SetMargin(a1, cxLeftWidth, cxRightWidth, cyTopHeight, cyBottomHeight, a6);
}

bool(__thiscall* UpdateMarginsDependentOnStyle)(void*);
bool __thiscall UpdateMarginsDependentOnStyle_hook(void* pThis) {
    int ret = UpdateMarginsDependentOnStyle(pThis);
    struct tagRECT Rect;
    struct _MARGINS a3;
    DWORD* windowData;
    int dwStyle;
    DWORD dwExStyle;
    int v8;
    LONG v9;
    int v10;
    int v11;
    LONG right;
    int v13;
    int v14;
    LONG v15;
    LONG bottom;

    windowData = (DWORD*)*((unsigned long long*)pThis + 91);
    dwStyle = windowData[25];
    dwExStyle = windowData[26];

    // CalculateOutsideMargins from Windows 7
    Rect.left = 0;
    Rect.top = 0;
    Rect.right = 0;
    Rect.bottom = 0;
    AdjustWindowRectEx(&Rect, dwStyle | 0x40000, 0, dwExStyle);
    v8 = windowData[16];
    v9 = windowData[17];
    v10 = -Rect.left;
    v11 = -Rect.top;
    if (v8 > -Rect.left)
        v10 = windowData[16];
    a3.cxLeftWidth = v8 - v10;
    right = Rect.right;
    if (v9 > Rect.right)
        right = v9;
    v13 = v9 - right;
    v14 = windowData[18];
    a3.cxRightWidth = v13;
    v15 = windowData[19];
    if (v14 > v11)
        v11 = v14;
    a3.cyTopHeight = v14 - v11;
    bottom = Rect.bottom;
    if (v15 > Rect.bottom)
        bottom = v15;
    a3.cyBottomHeight = v15 - bottom;
    
    // Check NC size
    if (windowData[16] > 0 && windowData[17] > 0 && windowData[18] > 0 && windowData[19] > 0) {
        SetMargin((struct _MARGINS*)((char*)pThis + 628), a3.cxLeftWidth,
                  a3.cxRightWidth, a3.cyTopHeight, a3.cyBottomHeight, 0);
    }

    return ret;
}

BOOL Wh_ModInit() {
    Wh_Log(L"Init");

    HMODULE uDWM = LoadLibraryW(L"uDWM.dll");

    if (!uDWM) {
        Wh_Log(L"Failed to load uDWM.dll");
        return FALSE;
    }

    WindhawkUtils::SYMBOL_HOOK symbolHooks[] = {
        {
            {L"private: bool __cdecl CTopLevelWindow::UpdateMarginsDependentOnStyle(void)"},
            (void**)&UpdateMarginsDependentOnStyle,
            (void*)UpdateMarginsDependentOnStyle_hook,
        },
        {
            {L"bool __cdecl SetMargin(struct _MARGINS *,int,int,int,int,struct _MARGINS const *)"},
            (void**)&SetMargin,
            (void*)SetMargin_hook,
        },
    };

    if (!WindhawkUtils::HookSymbols(uDWM, symbolHooks, ARRAYSIZE(symbolHooks))) {
        Wh_Log(L"Error hooking");
        return FALSE;
    }
    return TRUE;
}

these broken borders also seem to be the same ones that other thick frame mods don't affect to begin with

TorutheRedFox avatar Jun 06 '24 21:06 TorutheRedFox

try this borders have blur and windows arent resizable not made by me https://raw.githubusercontent.com/ramensoftware/windhawk-mods/2f162c3f58d4ef04f6d69ec7865f0c2db2f33ba1/mods/force-thick-frames-plus.wh.cpp

yuri980 avatar Jun 08 '24 11:06 yuri980

try this borders have blur and windows arent resizable not made by me https://raw.githubusercontent.com/ramensoftware/windhawk-mods/2f162c3f58d4ef04f6d69ec7865f0c2db2f33ba1/mods/force-thick-frames-plus.wh.cpp

this just tries to force an attribute onto a window, which comes with a number of issues

TorutheRedFox avatar Jun 08 '24 14:06 TorutheRedFox