Skip to content

Commit

Permalink
Better ListView theme (OpenNcThemeData hook)
Browse files Browse the repository at this point in the history
  • Loading branch information
DartVanya committed Oct 22, 2024
1 parent 52a5063 commit 7f44475
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 52 deletions.
84 changes: 59 additions & 25 deletions SystemInformer/delayhook.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ static BOOLEAN PhDefaultEnableStreamerMode = FALSE;
static BOOLEAN PhDefaultEnableThemeAcrylicWindowSupport = FALSE;
static BOOLEAN PhDefaultEnableThemeAnimation = FALSE;

BOOL(WINAPI* PhIsDarkModeAllowedForWindow_I)(
_In_ HWND WindowHandle
) = NULL;

LRESULT CALLBACK PhMenuWindowHookProcedure(
_In_ HWND WindowHandle,
_In_ UINT WindowMessage,
Expand Down Expand Up @@ -234,7 +238,7 @@ LRESULT CALLBACK PhStaticWindowHookProcedure(
{
RECT rectClient;
GetClientRect(WindowHandle, &rectClient);
InflateRect(&rectClient, 2, 2);
PhInflateRect(&rectClient, 2, 2);
MapWindowRect(WindowHandle, ParentHandle, &rectClient);
InvalidateRect(ParentHandle, &rectClient, TRUE); // fix the annoying white border left by the previous active control
}
Expand Down Expand Up @@ -925,40 +929,35 @@ LRESULT CALLBACK PhHeaderWindowHookProcedure(
{
CREATESTRUCT* createStruct = (CREATESTRUCT*)lParam;

// Don't apply header theme for unsupported dialogs: Advanced Security and Digital Signature Details (Dart Vanya)
if (!FindWindowEx(GetAncestor(WindowHandle, GA_ROOT), NULL, L"DirectUIHWND", NULL) &&
!FindWindowEx(GetParent(createStruct->hwndParent), NULL, L"NativeFontCtl", NULL))
if (createStruct->hwndParent)
{
if (createStruct->hwndParent)
{
WCHAR windowClassName[MAX_PATH];
WCHAR windowClassName[MAX_PATH];

if (!GetClassName(createStruct->hwndParent, windowClassName, RTL_NUMBER_OF(windowClassName)))
windowClassName[0] = UNICODE_NULL;
if (!GetClassName(createStruct->hwndParent, windowClassName, RTL_NUMBER_OF(windowClassName)))
windowClassName[0] = UNICODE_NULL;

if (PhEqualStringZ(windowClassName, L"PhTreeNew", FALSE))
{
LONG_PTR windowStyle = PhGetWindowStyle(createStruct->hwndParent);
if (PhEqualStringZ(windowClassName, L"PhTreeNew", FALSE))
{
LONG_PTR windowStyle = PhGetWindowStyle(createStruct->hwndParent);

if (BooleanFlagOn(windowStyle, TN_STYLE_CUSTOM_HEADERDRAW))
{
PhSetControlTheme(WindowHandle, L"DarkMode_ItemsView");
if (BooleanFlagOn(windowStyle, TN_STYLE_CUSTOM_HEADERDRAW))
{
PhSetControlTheme(WindowHandle, L"DarkMode_ItemsView");

return CallWindowProc(PhDefaultHeaderWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);
}
return CallWindowProc(PhDefaultHeaderWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);
}
}
}

context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_HEADER_CONTEXT));
context->ThemeHandle = PhOpenThemeData(WindowHandle, VSCLASS_HEADER, PhGetWindowDpi(WindowHandle));
context->CursorPos.x = LONG_MIN;
context->CursorPos.y = LONG_MIN;
PhSetWindowContext(WindowHandle, LONG_MAX, context);
context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_HEADER_CONTEXT));
context->ThemeHandle = PhOpenThemeData(WindowHandle, VSCLASS_HEADER, PhGetWindowDpi(WindowHandle));
context->CursorPos.x = LONG_MIN;
context->CursorPos.y = LONG_MIN;
PhSetWindowContext(WindowHandle, LONG_MAX, context);

PhSetControlTheme(WindowHandle, L"DarkMode_ItemsView");
PhSetControlTheme(WindowHandle, L"DarkMode_ItemsView");

InvalidateRect(WindowHandle, NULL, FALSE);
}
InvalidateRect(WindowHandle, NULL, FALSE);
}
else
{
Expand Down Expand Up @@ -1043,6 +1042,17 @@ LRESULT CALLBACK PhHeaderWindowHookProcedure(
break;
case WM_PAINT:
{
// Don't apply header theme for unsupported dialogs: Advanced Security, Digital Signature Details, etc. (Dart Vanya)
if (!PhIsDarkModeAllowedForWindow_I(GetParent(WindowHandle)))
{
PhRemoveWindowContext(WindowHandle, LONG_MAX);
if (context->ThemeHandle)
PhCloseThemeData(context->ThemeHandle);
PhFree(context);
PhSetControlTheme(WindowHandle, L"Explorer");
break;
}

//PAINTSTRUCT ps;
//HDC BufferedHDC;
//HPAINTBUFFER BufferedPaint;
Expand Down Expand Up @@ -1312,6 +1322,12 @@ static HRESULT(WINAPI* PhDefaultGetThemeColor)(
_Out_ COLORREF* pColor
) = NULL;

// uxtheme.dll ordinal 49
static HTHEME(WINAPI* PhDefaultOpenNcThemeData)(
_In_ HWND hwnd,
_In_ LPCWSTR pszClassList
) = NULL;

static BOOL (WINAPI* PhDefaultSystemParametersInfo)(
_In_ UINT uiAction,
_In_ UINT uiParam,
Expand Down Expand Up @@ -1769,6 +1785,20 @@ HRESULT PhGetThemeColorHook(
return retVal;
}

HTHEME PhOpenNcThemeDataHook(
_In_ HWND hwnd,
_In_ LPCWSTR pszClassList
)
{
if (PhEqualStringZ((PWSTR)pszClassList, VSCLASS_SCROLLBAR, TRUE) &&
PhIsDarkModeAllowedForWindow_I(hwnd))
{
return PhDefaultOpenNcThemeData(NULL, L"Explorer::ScrollBar");
}

return PhDefaultOpenNcThemeData(hwnd, pszClassList);
}

BOOLEAN CALLBACK PhInitializeTaskDialogTheme(
_In_ HWND WindowHandle,
_In_opt_ PVOID CallbackData
Expand Down Expand Up @@ -1987,6 +2017,8 @@ VOID PhRegisterDetoursHooks(
PhDefaultDrawThemeText = PhGetDllBaseProcedureAddress(baseAddress, "DrawThemeText", 0);
PhDefaultDrawThemeTextEx = PhGetDllBaseProcedureAddress(baseAddress, "DrawThemeTextEx", 0);
PhDefaultGetThemeColor = PhGetDllBaseProcedureAddress(baseAddress, "GetThemeColor", 0);
PhIsDarkModeAllowedForWindow_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 137);
PhDefaultOpenNcThemeData = PhGetDllBaseProcedureAddress(baseAddress, NULL, 49);
}

if (baseAddress = PhGetLoaderEntryDllBaseZ(L"Comctl32.dll"))
Expand Down Expand Up @@ -2014,6 +2046,8 @@ VOID PhRegisterDetoursHooks(
goto CleanupExit;
if (!NT_SUCCESS(status = DetourAttach((PVOID)&PhDefaultGetThemeColor, (PVOID)PhGetThemeColorHook)))
goto CleanupExit;
if (!NT_SUCCESS(status = DetourAttach((PVOID)&PhDefaultOpenNcThemeData, (PVOID)PhOpenNcThemeDataHook)))
goto CleanupExit;
if (!NT_SUCCESS(status = DetourAttach((PVOID)&PhDefaultTaskDialogIndirect, (PVOID)PhTaskDialogIndirectHook)))
goto CleanupExit;
}
Expand Down
18 changes: 15 additions & 3 deletions phlib/theme.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ VOID PhInitializeWindowTheme(
AllowDarkModeForWindow_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 133);
SetPreferredAppMode_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 135);
//FlushMenuThemes_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 136);
IsDarkModeAllowedForWindow_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 137);
}

if (SetPreferredAppMode_I)
Expand Down Expand Up @@ -240,8 +241,17 @@ VOID PhInitializeWindowTheme(

if (defaultWindowProc != PhpThemeWindowSubclassProc)
{
WCHAR windowClassName[MAX_PATH];
PhSetWindowContext(WindowHandle, LONG_MAX, defaultWindowProc);
SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowSubclassProc);

if (!GetClassName(WindowHandle, windowClassName, RTL_NUMBER_OF(windowClassName)))
windowClassName[0] = UNICODE_NULL;
if ((PhEqualStringZ(windowClassName, L"PhTreeNew", FALSE) || PhEqualStringZ(windowClassName, WC_LISTVIEW, FALSE)) &&
WindowsVersion >= WINDOWS_10_RS5)
{
AllowDarkModeForWindow_I(WindowHandle, TRUE); // HACK for dynamically generated plugin tabs
}
}

PhEnumChildWindows(
Expand Down Expand Up @@ -742,7 +752,9 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows(
// PhSetControlTheme(tooltipWindow, L"");
// break;
//case 1: // Old colors
PhWindowThemeSetDarkMode(WindowHandle, TRUE);
//PhWindowThemeSetDarkMode(WindowHandle, TRUE);
AllowDarkModeForWindow_I(WindowHandle, TRUE);
PhSetControlTheme(WindowHandle, L"DarkMode_ItemsView");
PhWindowThemeSetDarkMode(tooltipWindow, TRUE);
}

Expand Down Expand Up @@ -821,6 +833,7 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows(
//case 1: // Old colors
PhWindowThemeSetDarkMode(tooltipWindow, TRUE);
PhWindowThemeSetDarkMode(WindowHandle, TRUE);
AllowDarkModeForWindow_I(WindowHandle, TRUE);
}

if (PhEnableThemeListviewBorder)
Expand Down Expand Up @@ -3270,12 +3283,11 @@ LRESULT CALLBACK PhpThemeWindowACLUISubclassProc(
{
HDC hdc = GetDC(WindowHandle);
RECT rectControl = customDraw->rc;
InflateRect(&rectControl, 2, 2);
PhInflateRect(&rectControl, 2, 2);
MapWindowRect(customDraw->hdr.hwndFrom, WindowHandle, &rectControl);
FillRect(hdc, &rectControl, PhThemeWindowBackgroundBrush); // fix the annoying white border left by the previous active control
ReleaseDC(WindowHandle, hdc);
}
return CDRF_DODEFAULT;
}
}
}
Expand Down
82 changes: 58 additions & 24 deletions tools/peview/delayhook.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ static BOOLEAN PhDefaultEnableStreamerMode = FALSE;
static BOOLEAN PhDefaultEnableThemeAcrylicWindowSupport = FALSE;
static BOOLEAN PhDefaultEnableThemeAnimation = FALSE;

BOOL(WINAPI* PhIsDarkModeAllowedForWindow_I)(
_In_ HWND WindowHandle
) = NULL;

LRESULT CALLBACK PhMenuWindowHookProcedure(
_In_ HWND WindowHandle,
_In_ UINT WindowMessage,
Expand Down Expand Up @@ -925,40 +929,35 @@ LRESULT CALLBACK PhHeaderWindowHookProcedure(
{
CREATESTRUCT* createStruct = (CREATESTRUCT*)lParam;

// Don't apply header theme for unsupported dialogs: Advanced Security and Digital Signature Details (Dart Vanya)
if (!FindWindowEx(GetAncestor(WindowHandle, GA_ROOT), NULL, L"DirectUIHWND", NULL) &&
!FindWindowEx(GetParent(createStruct->hwndParent), NULL, L"NativeFontCtl", NULL))
if (createStruct->hwndParent)
{
if (createStruct->hwndParent)
{
WCHAR windowClassName[MAX_PATH];
WCHAR windowClassName[MAX_PATH];

if (!GetClassName(createStruct->hwndParent, windowClassName, RTL_NUMBER_OF(windowClassName)))
windowClassName[0] = UNICODE_NULL;
if (!GetClassName(createStruct->hwndParent, windowClassName, RTL_NUMBER_OF(windowClassName)))
windowClassName[0] = UNICODE_NULL;

if (PhEqualStringZ(windowClassName, L"PhTreeNew", FALSE))
{
LONG_PTR windowStyle = PhGetWindowStyle(createStruct->hwndParent);
if (PhEqualStringZ(windowClassName, L"PhTreeNew", FALSE))
{
LONG_PTR windowStyle = PhGetWindowStyle(createStruct->hwndParent);

if (BooleanFlagOn(windowStyle, TN_STYLE_CUSTOM_HEADERDRAW))
{
PhSetControlTheme(WindowHandle, L"DarkMode_ItemsView");
if (BooleanFlagOn(windowStyle, TN_STYLE_CUSTOM_HEADERDRAW))
{
PhSetControlTheme(WindowHandle, L"DarkMode_ItemsView");

return CallWindowProc(PhDefaultHeaderWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);
}
return CallWindowProc(PhDefaultHeaderWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);
}
}
}

context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_HEADER_CONTEXT));
context->ThemeHandle = PhOpenThemeData(WindowHandle, VSCLASS_HEADER, PhGetWindowDpi(WindowHandle));
context->CursorPos.x = LONG_MIN;
context->CursorPos.y = LONG_MIN;
PhSetWindowContext(WindowHandle, LONG_MAX, context);
context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_HEADER_CONTEXT));
context->ThemeHandle = PhOpenThemeData(WindowHandle, VSCLASS_HEADER, PhGetWindowDpi(WindowHandle));
context->CursorPos.x = LONG_MIN;
context->CursorPos.y = LONG_MIN;
PhSetWindowContext(WindowHandle, LONG_MAX, context);

PhSetControlTheme(WindowHandle, L"DarkMode_ItemsView");
PhSetControlTheme(WindowHandle, L"DarkMode_ItemsView");

InvalidateRect(WindowHandle, NULL, FALSE);
}
InvalidateRect(WindowHandle, NULL, FALSE);
}
else
{
Expand Down Expand Up @@ -1043,6 +1042,17 @@ LRESULT CALLBACK PhHeaderWindowHookProcedure(
break;
case WM_PAINT:
{
// Don't apply header theme for unsupported dialogs: Advanced Security, Digital Signature Details, etc. (Dart Vanya)
if (!PhIsDarkModeAllowedForWindow_I(GetParent(WindowHandle)))
{
PhRemoveWindowContext(WindowHandle, LONG_MAX);
if (context->ThemeHandle)
PhCloseThemeData(context->ThemeHandle);
PhFree(context);
PhSetControlTheme(WindowHandle, L"Explorer");
break;
}

//PAINTSTRUCT ps;
//HDC BufferedHDC;
//HPAINTBUFFER BufferedPaint;
Expand Down Expand Up @@ -1312,6 +1322,12 @@ static HRESULT(WINAPI* PhDefaultGetThemeColor)(
_Out_ COLORREF* pColor
) = NULL;

// uxtheme.dll ordinal 49
static HTHEME(WINAPI* PhDefaultOpenNcThemeData)(
_In_ HWND hwnd,
_In_ LPCWSTR pszClassList
) = NULL;

static BOOL (WINAPI* PhDefaultSystemParametersInfo)(
_In_ UINT uiAction,
_In_ UINT uiParam,
Expand Down Expand Up @@ -1754,6 +1770,20 @@ HRESULT PhGetThemeColorHook(
return retVal;
}

HTHEME PhOpenNcThemeDataHook(
_In_ HWND hwnd,
_In_ LPCWSTR pszClassList
)
{
if (PhEqualStringZ((PWSTR)pszClassList, VSCLASS_SCROLLBAR, TRUE) &&
PhIsDarkModeAllowedForWindow_I(hwnd))
{
return PhDefaultOpenNcThemeData(NULL, L"Explorer::ScrollBar");
}

return PhDefaultOpenNcThemeData(hwnd, pszClassList);
}

BOOLEAN CALLBACK PhInitializeTaskDialogTheme(
_In_ HWND WindowHandle,
_In_opt_ PVOID CallbackData
Expand Down Expand Up @@ -1972,6 +2002,8 @@ VOID PhRegisterDetoursHooks(
PhDefaultDrawThemeText = PhGetDllBaseProcedureAddress(baseAddress, "DrawThemeText", 0);
PhDefaultDrawThemeTextEx = PhGetDllBaseProcedureAddress(baseAddress, "DrawThemeTextEx", 0);
PhDefaultGetThemeColor = PhGetDllBaseProcedureAddress(baseAddress, "GetThemeColor", 0);
PhIsDarkModeAllowedForWindow_I = PhGetDllBaseProcedureAddress(baseAddress, NULL, 137);
PhDefaultOpenNcThemeData = PhGetDllBaseProcedureAddress(baseAddress, NULL, 49);
}

if (baseAddress = PhGetLoaderEntryDllBaseZ(L"Comctl32.dll"))
Expand Down Expand Up @@ -1999,6 +2031,8 @@ VOID PhRegisterDetoursHooks(
goto CleanupExit;
if (!NT_SUCCESS(status = DetourAttach((PVOID)&PhDefaultGetThemeColor, (PVOID)PhGetThemeColorHook)))
goto CleanupExit;
if (!NT_SUCCESS(status = DetourAttach((PVOID)&PhDefaultOpenNcThemeData, (PVOID)PhOpenNcThemeDataHook)))
goto CleanupExit;
if (!NT_SUCCESS(status = DetourAttach((PVOID)&PhDefaultTaskDialogIndirect, (PVOID)PhTaskDialogIndirectHook)))
goto CleanupExit;
}
Expand Down

0 comments on commit 7f44475

Please sign in to comment.