Skip to content

Commit

Permalink
Improve streamer mode for ComboBox and ToolTips
Browse files Browse the repository at this point in the history
  • Loading branch information
DartVanya committed Dec 6, 2024
1 parent 64bc003 commit 29f24b5
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 194 deletions.
3 changes: 0 additions & 3 deletions SystemInformer/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1217,9 +1217,6 @@ VOID PhpInitializeSettings(
PhEnableKsiSupport = !!PhGetIntegerSetting(L"KsiEnable") && !PhStartupParameters.NoKph && !PhIsExecutingInWow64();
PhEnableKsiWarnings = !!PhGetIntegerSetting(L"KsiEnableWarnings");

if (!PhThemeWindowBackgroundBrush)
PhThemeWindowBackgroundBrush = CreateSolidBrush(PhThemeWindowBackgroundColor);

// If AppMode is set to PreferredAppModeDarkOnDark, PhShouldAppsUseDarkMode should return current Windows app color mode.
// It's weird that sometimes it can return incorrect inverted value (idk why).
// In this case use PhGetAppsUseLightTheme() to retrieve raw value from registry.
Expand Down
218 changes: 41 additions & 177 deletions phlib/delayhook.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@
#include "settings.h"

// https://learn.microsoft.com/en-us/windows/win32/winmsg/about-window-procedures#window-procedure-superclassing
static WNDPROC PhDefaultMenuWindowProcedure = NULL;
static WNDPROC PhDefaultDialogWindowProcedure = NULL;
static WNDPROC PhDefaultMenuWindowProcedure = NULL;
static WNDPROC PhDefaultRebarWindowProcedure = NULL;
static WNDPROC PhDefaultComboBoxWindowProcedure = NULL;
static WNDPROC PhDefaultStaticWindowProcedure = NULL;
static WNDPROC PhDefaultStatusbarWindowProcedure = NULL;
static WNDPROC PhDefaultEditWindowProcedure = NULL;
static WNDPROC PhDefaultHeaderWindowProcedure = NULL;
static WNDPROC PhDefaultToolTipWindowProcedure = NULL;

LRESULT CALLBACK PhMenuWindowHookProcedure(
_In_ HWND WindowHandle,
Expand Down Expand Up @@ -115,14 +115,24 @@ LRESULT CALLBACK PhDialogWindowHookProcedure(
SetWindowDisplayAffinity(WindowHandle, WDA_EXCLUDEFROMCAPTURE);
}

if (PhEnableThemeSupport && PhEnableThemeAcrylicWindowSupport)
if (PhEnableThemeAcrylicWindowSupport)
{
// Note: DWM crashes if called from WM_NCCREATE (dmex)
PhSetWindowAcrylicCompositionColor(WindowHandle, MakeABGRFromCOLORREF(0, RGB(10, 10, 10)), TRUE);
}
}
}
break;
case WM_COMMAND:
if (PhEnableStreamerMode && GET_WM_COMMAND_CMD(wParam, lParam) == CBN_DROPDOWN)
{
COMBOBOXINFO info = { sizeof(COMBOBOXINFO) };
if (SendMessage(GET_WM_COMMAND_HWND(wParam, lParam), CB_GETCOMBOBOXINFO, 0, (LPARAM)&info) && info.hwndList)
{
SetWindowDisplayAffinity(info.hwndList, WDA_EXCLUDEFROMCAPTURE);
}
}
break;
}

return CallWindowProc(PhDefaultDialogWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);
Expand Down Expand Up @@ -153,27 +163,21 @@ LRESULT CALLBACK PhRebarWindowHookProcedure(
return CallWindowProc(PhDefaultRebarWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);
}

LRESULT CALLBACK PhComboBoxWindowHookProcedure(
LRESULT CALLBACK PhToolTipWindowHookProcedure(
_In_ HWND WindowHandle,
_In_ UINT WindowMessage,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
LRESULT result = CallWindowProc(PhDefaultComboBoxWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);
LRESULT result = CallWindowProc(PhDefaultToolTipWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);

switch (WindowMessage)
{
case WM_NCCREATE:
if (PhEnableStreamerMode)
{
//CREATESTRUCT* createStruct = (CREATESTRUCT*)lParam;
COMBOBOXINFO info = { sizeof(COMBOBOXINFO) };

if (SendMessage(WindowHandle, CB_GETCOMBOBOXINFO, 0, (LPARAM)&info) && info.hwndList)
{
SetWindowDisplayAffinity(info.hwndList, WDA_EXCLUDEFROMCAPTURE);
}
SetWindowDisplayAffinity(WindowHandle, WDA_EXCLUDEFROMCAPTURE);
}
break;
}
Expand Down Expand Up @@ -1096,160 +1100,25 @@ LRESULT CALLBACK PhHeaderWindowHookProcedure(
return CallWindowProc(PhDefaultHeaderWindowProcedure, WindowHandle, WindowMessage, wParam, lParam);
}

VOID PhRegisterDialogSuperClass(
VOID
)
{
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };

if (!GetClassInfoEx(NULL, L"#32770", &wcex))
return;

PhDefaultDialogWindowProcedure = wcex.lpfnWndProc;
wcex.lpfnWndProc = PhDialogWindowHookProcedure;
wcex.style = wcex.style | CS_PARENTDC | CS_GLOBALCLASS;

UnregisterClass(L"#32770", NULL);
if (RegisterClassEx(&wcex) == INVALID_ATOM)
{
PhShowStatus(NULL, L"Unable to register window class.", 0, GetLastError());
}
}

VOID PhRegisterMenuSuperClass(
VOID
)
{
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };

if (!GetClassInfoEx(NULL, L"#32768", &wcex))
return;

PhDefaultMenuWindowProcedure = wcex.lpfnWndProc;
wcex.lpfnWndProc = PhMenuWindowHookProcedure;
wcex.style = wcex.style | CS_PARENTDC | CS_GLOBALCLASS;

UnregisterClass(L"#32768", NULL);
if (RegisterClassEx(&wcex) == INVALID_ATOM)
{
PhShowStatus(NULL, L"Unable to register window class.", 0, GetLastError());
}
}

VOID PhRegisterRebarSuperClass(
VOID
)
{
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };

if (!GetClassInfoEx(NULL, REBARCLASSNAME, &wcex))
return;

PhDefaultRebarWindowProcedure = wcex.lpfnWndProc;
wcex.lpfnWndProc = PhRebarWindowHookProcedure;
wcex.style = wcex.style | CS_PARENTDC | CS_GLOBALCLASS;

UnregisterClass(REBARCLASSNAME, NULL);
if (RegisterClassEx(&wcex) == INVALID_ATOM)
{
PhShowStatus(NULL, L"Unable to register window class.", 0, GetLastError());
}
}

VOID PhRegisterComboBoxSuperClass(
VOID
)
{
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };

if (!GetClassInfoEx(NULL, WC_COMBOBOX, &wcex))
return;

PhDefaultComboBoxWindowProcedure = wcex.lpfnWndProc;
wcex.lpfnWndProc = PhComboBoxWindowHookProcedure;
wcex.style = wcex.style | CS_PARENTDC | CS_GLOBALCLASS;

UnregisterClass(WC_COMBOBOX, NULL);
if (RegisterClassEx(&wcex) == INVALID_ATOM)
{
PhShowStatus(NULL, L"Unable to register window class.", 0, GetLastError());
}
}

VOID PhRegisterStaticSuperClass(
VOID
VOID PhRegisterSuperClassCommon(
_In_ PWSTR ClassName,
_In_ WNDPROC HookProc,
_Out_ WNDPROC *OldWndProc
)
{
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };

if (!GetClassInfoEx(NULL, WC_STATIC, &wcex))
return;

PhDefaultStaticWindowProcedure = wcex.lpfnWndProc;
wcex.lpfnWndProc = PhStaticWindowHookProcedure;
wcex.style = wcex.style | CS_PARENTDC | CS_GLOBALCLASS;

UnregisterClass(WC_STATIC, NULL);
if (RegisterClassEx(&wcex) == INVALID_ATOM)
if (!GetClassInfoEx(NULL, ClassName, &wcex))
{
PhShowStatus(NULL, L"Unable to register window class.", 0, GetLastError());
}
}

VOID PhRegisterStatusBarSuperClass(
VOID
)
{
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };

if (!GetClassInfoEx(NULL, STATUSCLASSNAME, &wcex))
*OldWndProc = NULL;
return;

PhDefaultStatusbarWindowProcedure = wcex.lpfnWndProc;
wcex.lpfnWndProc = PhStatusBarWindowHookProcedure;
wcex.style = wcex.style | CS_PARENTDC | CS_GLOBALCLASS;

UnregisterClass(STATUSCLASSNAME, NULL);
if (RegisterClassEx(&wcex) == INVALID_ATOM)
{
PhShowStatus(NULL, L"Unable to register window class.", 0, GetLastError());
}
}

VOID PhRegisterEditSuperClass(
VOID
)
{
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };

if (!GetClassInfoEx(NULL, WC_EDIT, &wcex))
return;

PhDefaultEditWindowProcedure = wcex.lpfnWndProc;
wcex.lpfnWndProc = PhEditWindowHookProcedure;
*OldWndProc = wcex.lpfnWndProc;
wcex.lpfnWndProc = HookProc;
wcex.style = wcex.style | CS_PARENTDC | CS_GLOBALCLASS;

UnregisterClass(WC_EDIT, NULL);
if (RegisterClassEx(&wcex) == INVALID_ATOM)
{
PhShowStatus(NULL, L"Unable to register window class.", 0, GetLastError());
}
}

VOID PhRegisterHeaderSuperClass(
VOID
)
{
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };

if (!GetClassInfoEx(NULL, WC_HEADER, &wcex))
return;

PhDefaultHeaderWindowProcedure = wcex.lpfnWndProc;
wcex.lpfnWndProc = PhHeaderWindowHookProcedure;
wcex.style = wcex.style | CS_PARENTDC | CS_GLOBALCLASS;

UnregisterClass(WC_HEADER, NULL);
UnregisterClass(ClassName, NULL);
if (RegisterClassEx(&wcex) == INVALID_ATOM)
{
PhShowStatus(NULL, L"Unable to register window class.", 0, GetLastError());
Expand Down Expand Up @@ -1502,23 +1371,18 @@ PhCreateWindowExHook(
SetWindowDisplayAffinity(windowHandle, WDA_EXCLUDEFROMCAPTURE);
}

if (PhEnableThemeSupport && PhEnableThemeAcrylicWindowSupport)
if (PhEnableThemeAcrylicWindowSupport)
{
PhSetWindowAcrylicCompositionColor(windowHandle, MakeABGRFromCOLORREF(0, RGB(10, 10, 10)), TRUE);
}
}
else
{
// Early subclassing of the SysLink control to eliminate blinking during page switches.
if (!IS_INTRESOURCE(lpClassName) && PhEqualStringZ(lpClassName, WC_LINK, TRUE))
if (!IS_INTRESOURCE(lpClassName) && PhEqualStringZ(lpClassName, WC_LINK, FALSE))
{
PhInitializeTaskDialogTheme(windowHandle, NULL);
}
else if (!IS_INTRESOURCE(lpClassName) && PhEqualStringZ(lpClassName, WC_BUTTON, TRUE) &&
PhGetWindowContext(GetAncestor(hWndParent, GA_ROOT), LONG_MAX))
{
PhSetControlTheme(windowHandle, L"DarkMode_Explorer");
}
}

return windowHandle;
Expand Down Expand Up @@ -1818,10 +1682,11 @@ BOOLEAN CALLBACK PhInitializeTaskDialogTheme(

if (RootDialogWindow && !windowHasContext)
{
if (PhEnableStreamerMode)
{
SetWindowDisplayAffinity(WindowHandle, WDA_EXCLUDEFROMCAPTURE);
}
// Handled by PhDialogWindowHookProcedure
//if (PhEnableStreamerMode)
//{
// SetWindowDisplayAffinity(WindowHandle, WDA_EXCLUDEFROMCAPTURE);
//}

PhInitializeThemeWindowFrame(WindowHandle);

Expand Down Expand Up @@ -2109,20 +1974,19 @@ VOID PhInitializeSuperclassControls(
PhEnableThemeAcrylicWindowSupport = PhEnableThemeAcrylicWindowSupport && PhEnableThemeSupport && PhIsThemeTransparencyEnabled();

// For early TaskDialog with PhStartupParameters.ShowOptions
if (!PhThemeWindowBackgroundBrush)
PhThemeWindowBackgroundBrush = CreateSolidBrush(PhThemeWindowBackgroundColor);
PhThemeWindowBackgroundBrush = CreateSolidBrush(PhThemeWindowBackgroundColor);

// Superclasses and detours now always installing that gives opportunity to flawlessly runtime theme switching.
// If theme is disabled they are just trampolined to original hooked procedures.
{
PhRegisterDialogSuperClass();
PhRegisterMenuSuperClass();
PhRegisterRebarSuperClass();
PhRegisterComboBoxSuperClass();
PhRegisterStaticSuperClass();
PhRegisterStatusBarSuperClass();
PhRegisterEditSuperClass();
PhRegisterHeaderSuperClass();
PhRegisterSuperClassCommon(L"#32770", PhDialogWindowHookProcedure, &PhDefaultDialogWindowProcedure);
PhRegisterSuperClassCommon(L"#32768", PhMenuWindowHookProcedure, &PhDefaultMenuWindowProcedure);
PhRegisterSuperClassCommon(REBARCLASSNAME, PhRebarWindowHookProcedure, &PhDefaultRebarWindowProcedure);
PhRegisterSuperClassCommon(WC_STATIC, PhStaticWindowHookProcedure, &PhDefaultStaticWindowProcedure);
PhRegisterSuperClassCommon(STATUSCLASSNAME, PhStatusBarWindowHookProcedure, &PhDefaultStatusbarWindowProcedure);
PhRegisterSuperClassCommon(WC_EDIT, PhEditWindowHookProcedure, &PhDefaultEditWindowProcedure);
PhRegisterSuperClassCommon(WC_HEADER, PhHeaderWindowHookProcedure, &PhDefaultHeaderWindowProcedure);
PhRegisterSuperClassCommon(TOOLTIPS_CLASS, PhToolTipWindowHookProcedure, &PhDefaultToolTipWindowProcedure);

PhRegisterDetoursHooks();
}
Expand Down
25 changes: 12 additions & 13 deletions phlib/theme.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,11 @@ VOID PhReInitializeTheme(

while (currentWindow = FindWindowEx(NULL, currentWindow, NULL, NULL))
{
WCHAR windowClassName[MAX_PATH];
ULONG processID = 0;

GetWindowThreadProcessId(currentWindow, &processID);

WCHAR windowClassName[MAX_PATH];

if (UlongToHandle(processID) == NtCurrentProcessId())
{
GETCLASSNAME_OR_NULL(currentWindow, windowClassName);
Expand Down Expand Up @@ -264,13 +263,19 @@ VOID PhReInitializeStreamerMode(

while (currentWindow = FindWindowEx(NULL, currentWindow, NULL, NULL))
{
WCHAR windowClassName[MAX_PATH];
ULONG processID = 0;

GetWindowThreadProcessId(currentWindow, &processID);

if (UlongToHandle(processID) == NtCurrentProcessId())
{
if ((PhGetWindowStyle(currentWindow) & WS_VISIBLE) == WS_VISIBLE)
GETCLASSNAME_OR_NULL(currentWindow, windowClassName);

if ((PhGetWindowStyle(currentWindow) & WS_VISIBLE) == WS_VISIBLE ||
PhEqualStringZ(windowClassName, TOOLTIPS_CLASS, FALSE)
//|| PhEqualStringZ(windowClassName, L"ComboLBox", FALSE)
)
{
SetWindowDisplayAffinity(currentWindow, Enable ? WDA_EXCLUDEFROMCAPTURE : WDA_NONE);
}
Expand All @@ -291,18 +296,13 @@ VOID PhReInitializeStreamerMode(

HRESULT PhSetWindowThemeAttribute(
_In_ HWND WindowHandle,
_In_ ULONG AttributeId,
_In_reads_bytes_(AttributeLength) PVOID Attribute,
_In_ ULONG AttributeLength
_In_ DWORD AttributeId,
_In_reads_bytes_(AttributeLength) LPCVOID Attribute,
_In_ DWORD AttributeLength
)
{
static PH_INITONCE initOnce = PH_INITONCE_INIT;
static HRESULT (WINAPI* DwmSetWindowAttribute_I)(
_In_ HWND WindowHandle,
_In_ ULONG AttributeId,
_In_reads_bytes_(AttributeLength) PVOID Attribute,
_In_ ULONG AttributeLength
);
static typeof(&DwmSetWindowAttribute) DwmSetWindowAttribute_I = nullptr;

if (PhBeginInitOnce(&initOnce))
{
Expand Down Expand Up @@ -3148,7 +3148,6 @@ LRESULT CALLBACK PhpThemeWindowComboBoxControlSubclassProc(
goto DefaultWndProc;
}

// BUG BUG BUG fix
return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam);

DefaultWndProc:
Expand Down
1 change: 0 additions & 1 deletion tools/peview/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ VOID PvUpdateCachedSettings(
{
PhMaxSizeUnit = PhGetIntegerSetting(L"MaxSizeUnit");
PhEnableSecurityAdvancedDialog = !!PhGetIntegerSetting(L"EnableSecurityAdvancedDialog");
PhEnableThemeSupport = PhIsThemeSupportEnabled();
PhThemeWindowForegroundColor = PhGetIntegerSetting(L"ThemeWindowForegroundColor");
COLORREF oldPhThemeWindowBackgroundColor = PhThemeWindowBackgroundColor;
PhThemeWindowBackgroundColor = PhGetIntegerSetting(L"ThemeWindowBackgroundColor");
Expand Down

0 comments on commit 29f24b5

Please sign in to comment.