Skip to content

Instantly share code, notes, and snippets.

@Starpelly
Last active March 5, 2025 14:30
Show Gist options
  • Save Starpelly/983a3a87caac900ffaad24406e8bb983 to your computer and use it in GitHub Desktop.
Save Starpelly/983a3a87caac900ffaad24406e8bb983 to your computer and use it in GitHub Desktop.
BeefIDE dark menus mod for Windhawk
// ==WindhawkMod==
// @id beefide-dark-mode
// @name BeefIDE Dark MenuBar
// @description Makes the menu bar dark themed
// @version 1.0
// @author Starpelly
// @github https://github.com/starpelly
// @homepage https://starpelly.com/
// @include BeefIDE.exe
// @compilerOptions -lcomctl32 -lgdi32 -luxtheme
// ==/WindhawkMod==
// ==WindhawkModReadme==
/*
# Dark Mode for BeefIDE
*/
// ==/WindhawkModReadme==
#include <commctrl.h>
#include <windhawk_api.h>
#define BFWindow L"BFWindow"
// wParam - TRUE to subclass, FALSE to unsubclass
// lParam - subclass data
UINT g_subclassRegisteredMsg = RegisterWindowMessage(
L"Windhawk_SetWindowSubclassFromAnyThread_beefide-dark-mode");
struct SET_WINDOW_SUBCLASS_FROM_ANY_THREAD_PARAM {
SUBCLASSPROC pfnSubclass;
UINT_PTR uIdSubclass;
DWORD_PTR dwRefData;
BOOL result;
};
LRESULT CALLBACK CallWndProcForWindowSubclass(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION) {
const CWPSTRUCT* cwp = (const CWPSTRUCT*)lParam;
if (cwp->message == g_subclassRegisteredMsg && cwp->wParam) {
SET_WINDOW_SUBCLASS_FROM_ANY_THREAD_PARAM* param =
(SET_WINDOW_SUBCLASS_FROM_ANY_THREAD_PARAM*)cwp->lParam;
param->result = SetWindowSubclass(
cwp->hwnd, param->pfnSubclass, param->uIdSubclass, param->dwRefData);
}
}
return CallNextHookEx(nullptr, nCode, wParam, lParam);
}
BOOL SetWindowSubclassFromAnyThread(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
DWORD dwThreadId = GetWindowThreadProcessId(hWnd, nullptr);
if (dwThreadId == 0) {
return FALSE;
}
if (dwThreadId == GetCurrentThreadId()) {
return SetWindowSubclass(hWnd, pfnSubclass, uIdSubclass, dwRefData);
}
HHOOK hook = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProcForWindowSubclass, nullptr, dwThreadId);
if (!hook) {
return FALSE;
}
SET_WINDOW_SUBCLASS_FROM_ANY_THREAD_PARAM param;
param.pfnSubclass = pfnSubclass;
param.uIdSubclass = uIdSubclass;
param.dwRefData = dwRefData;
param.result = FALSE;
SendMessage(hWnd, g_subclassRegisteredMsg, TRUE, (WPARAM)&param);
UnhookWindowsHookEx(hook);
return param.result;
}
#pragma region DarkMode.cpp
/*
* Code taken from BeefIDE++:
* https://github.com/notepad-plus-plus/notepad-plus-plus/blob/bab3573be708bb908b8080e3e2007ea78a7f1932/PowerEditor/src/DarkMode/DarkMode.cpp
* Refer to the license in the repository above
*/
#include <uxtheme.h>
#include <vssym32.h>
enum IMMERSIVE_HC_CACHE_MODE
{
IHCM_USE_CACHED_VALUE,
IHCM_REFRESH
};
// 1903 18362
enum class PreferredAppMode
{
Default,
AllowDark,
ForceDark,
ForceLight,
Max
};
enum WINDOWCOMPOSITIONATTRIB
{
WCA_UNDEFINED = 0,
WCA_NCRENDERING_ENABLED = 1,
WCA_NCRENDERING_POLICY = 2,
WCA_TRANSITIONS_FORCEDISABLED = 3,
WCA_ALLOW_NCPAINT = 4,
WCA_CAPTION_BUTTON_BOUNDS = 5,
WCA_NONCLIENT_RTL_LAYOUT = 6,
WCA_FORCE_ICONIC_REPRESENTATION = 7,
WCA_EXTENDED_FRAME_BOUNDS = 8,
WCA_HAS_ICONIC_BITMAP = 9,
WCA_THEME_ATTRIBUTES = 10,
WCA_NCRENDERING_EXILED = 11,
WCA_NCADORNMENTINFO = 12,
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
WCA_VIDEO_OVERLAY_ACTIVE = 14,
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
WCA_DISALLOW_PEEK = 16,
WCA_CLOAK = 17,
WCA_CLOAKED = 18,
WCA_ACCENT_POLICY = 19,
WCA_FREEZE_REPRESENTATION = 20,
WCA_EVER_UNCLOAKED = 21,
WCA_VISUAL_OWNER = 22,
WCA_HOLOGRAPHIC = 23,
WCA_EXCLUDED_FROM_DDA = 24,
WCA_PASSIVEUPDATEMODE = 25,
WCA_USEDARKMODECOLORS = 26,
WCA_LAST = 27
};
struct WINDOWCOMPOSITIONATTRIBDATA
{
WINDOWCOMPOSITIONATTRIB Attrib;
PVOID pvData;
SIZE_T cbData;
};
using fnRtlGetNtVersionNumbers = void (WINAPI *)(LPDWORD major, LPDWORD minor, LPDWORD build);
using fnSetWindowCompositionAttribute = BOOL (WINAPI *)(HWND hWnd, WINDOWCOMPOSITIONATTRIBDATA*);
// 1809 17763
using fnShouldAppsUseDarkMode = bool (WINAPI *)(); // ordinal 132
using fnAllowDarkModeForWindow = bool (WINAPI *)(HWND hWnd, bool allow); // ordinal 133
using fnAllowDarkModeForApp = bool (WINAPI *)(bool allow); // ordinal 135, in 1809
using fnFlushMenuThemes = void (WINAPI *)(); // ordinal 136
using fnRefreshImmersiveColorPolicyState = void (WINAPI *)(); // ordinal 104
using fnIsDarkModeAllowedForWindow = bool (WINAPI *)(HWND hWnd); // ordinal 137
using fnGetIsImmersiveColorUsingHighContrast = bool (WINAPI *)(IMMERSIVE_HC_CACHE_MODE mode); // ordinal 106
using fnOpenNcThemeData = HTHEME(WINAPI *)(HWND hWnd, LPCWSTR pszClassList); // ordinal 49
// 1903 18362
using fnShouldSystemUseDarkMode = bool (WINAPI *)(); // ordinal 138
using fnSetPreferredAppMode = PreferredAppMode (WINAPI *)(PreferredAppMode appMode); // ordinal 135, in 1903
using fnIsDarkModeAllowedForApp = bool (WINAPI *)(); // ordinal 139
fnSetWindowCompositionAttribute _SetWindowCompositionAttribute = nullptr;
fnShouldAppsUseDarkMode _ShouldAppsUseDarkMode = nullptr;
fnAllowDarkModeForWindow _AllowDarkModeForWindow = nullptr;
fnAllowDarkModeForApp _AllowDarkModeForApp = nullptr;
fnFlushMenuThemes _FlushMenuThemes = nullptr;
fnRefreshImmersiveColorPolicyState _RefreshImmersiveColorPolicyState = nullptr;
fnIsDarkModeAllowedForWindow _IsDarkModeAllowedForWindow = nullptr;
fnGetIsImmersiveColorUsingHighContrast _GetIsImmersiveColorUsingHighContrast = nullptr;
fnOpenNcThemeData _OpenNcThemeData = nullptr;
// 1903 18362
//fnShouldSystemUseDarkMode _ShouldSystemUseDarkMode = nullptr;
fnSetPreferredAppMode _SetPreferredAppMode = nullptr;
bool g_darkModeSupported = false;
bool g_darkModeEnabled = false;
DWORD g_buildNumber = 0;
bool ShouldAppsUseDarkMode()
{
if (!_ShouldAppsUseDarkMode)
{
return false;
}
return _ShouldAppsUseDarkMode();
}
bool AllowDarkModeForWindow(HWND hWnd, bool allow)
{
if (g_darkModeSupported && _AllowDarkModeForWindow)
return _AllowDarkModeForWindow(hWnd, allow);
return false;
}
bool IsHighContrast()
{
HIGHCONTRASTW highContrast = { sizeof(highContrast) };
if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), &highContrast, FALSE))
return highContrast.dwFlags & HCF_HIGHCONTRASTON;
return false;
}
void SetTitleBarThemeColor(HWND hWnd, BOOL dark)
{
if (g_buildNumber < 18362)
SetPropW(hWnd, L"UseImmersiveDarkModeColors", reinterpret_cast<HANDLE>(static_cast<INT_PTR>(dark)));
else if (_SetWindowCompositionAttribute)
{
WINDOWCOMPOSITIONATTRIBDATA data = { WCA_USEDARKMODECOLORS, &dark, sizeof(dark) };
_SetWindowCompositionAttribute(hWnd, &data);
}
}
void RefreshTitleBarThemeColor(HWND hWnd)
{
BOOL dark = FALSE;
if (_IsDarkModeAllowedForWindow && _ShouldAppsUseDarkMode)
{
if (_IsDarkModeAllowedForWindow(hWnd) && _ShouldAppsUseDarkMode() && !IsHighContrast())
{
dark = TRUE;
}
}
SetTitleBarThemeColor(hWnd, dark);
}
bool IsColorSchemeChangeMessage(LPARAM lParam)
{
bool is = false;
if (lParam && (0 == lstrcmpi(reinterpret_cast<LPCWCH>(lParam), L"ImmersiveColorSet")) && _RefreshImmersiveColorPolicyState)
{
_RefreshImmersiveColorPolicyState();
is = true;
}
if (_GetIsImmersiveColorUsingHighContrast)
_GetIsImmersiveColorUsingHighContrast(IHCM_REFRESH);
return is;
}
bool IsColorSchemeChangeMessage(UINT message, LPARAM lParam)
{
if (message == WM_SETTINGCHANGE)
return IsColorSchemeChangeMessage(lParam);
return false;
}
void AllowDarkModeForApp(bool allow)
{
if (_AllowDarkModeForApp)
_AllowDarkModeForApp(allow);
else if (_SetPreferredAppMode)
_SetPreferredAppMode(allow ? PreferredAppMode::ForceDark : PreferredAppMode::Default);
}
void FlushMenuThemes()
{
if (_FlushMenuThemes)
{
_FlushMenuThemes();
}
}
constexpr bool CheckBuildNumber(DWORD buildNumber)
{
return (buildNumber == 17763 || // 1809
buildNumber == 18362 || // 1903
buildNumber == 18363 || // 1909
buildNumber == 19041 || // 2004
buildNumber == 19042 || // 20H2
buildNumber == 19043 || // 21H1
buildNumber == 19044 || // 21H2
(buildNumber > 19044 && buildNumber < 22000) || // Windows 10 any version > 21H2
buildNumber >= 22000); // Windows 11 insider builds
}
void InitDarkMode()
{
fnRtlGetNtVersionNumbers RtlGetNtVersionNumbers = nullptr;
HMODULE hNtdllModule = GetModuleHandle(L"ntdll.dll");
if (hNtdllModule)
{
RtlGetNtVersionNumbers = reinterpret_cast<fnRtlGetNtVersionNumbers>(GetProcAddress(hNtdllModule, "RtlGetNtVersionNumbers"));
}
if (RtlGetNtVersionNumbers)
{
DWORD major, minor;
RtlGetNtVersionNumbers(&major, &minor, &g_buildNumber);
g_buildNumber &= ~0xF0000000;
if (major == 10 && minor == 0 && CheckBuildNumber(g_buildNumber))
{
HMODULE hUxtheme = LoadLibraryEx(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (hUxtheme)
{
_OpenNcThemeData = reinterpret_cast<fnOpenNcThemeData>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(49)));
_RefreshImmersiveColorPolicyState = reinterpret_cast<fnRefreshImmersiveColorPolicyState>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(104)));
_GetIsImmersiveColorUsingHighContrast = reinterpret_cast<fnGetIsImmersiveColorUsingHighContrast>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(106)));
_ShouldAppsUseDarkMode = reinterpret_cast<fnShouldAppsUseDarkMode>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(132)));
_AllowDarkModeForWindow = reinterpret_cast<fnAllowDarkModeForWindow>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133)));
auto ord135 = GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135));
if (g_buildNumber < 18362)
_AllowDarkModeForApp = reinterpret_cast<fnAllowDarkModeForApp>(ord135);
else
_SetPreferredAppMode = reinterpret_cast<fnSetPreferredAppMode>(ord135);
_FlushMenuThemes = reinterpret_cast<fnFlushMenuThemes>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(136)));
_IsDarkModeAllowedForWindow = reinterpret_cast<fnIsDarkModeAllowedForWindow>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(137)));
HMODULE hUser32Module = GetModuleHandleW(L"user32.dll");
if (hUser32Module)
{
_SetWindowCompositionAttribute = reinterpret_cast<fnSetWindowCompositionAttribute>(GetProcAddress(hUser32Module, "SetWindowCompositionAttribute"));
}
if (_OpenNcThemeData &&
_RefreshImmersiveColorPolicyState &&
_ShouldAppsUseDarkMode &&
_AllowDarkModeForWindow &&
(_AllowDarkModeForApp || _SetPreferredAppMode) &&
_FlushMenuThemes &&
_IsDarkModeAllowedForWindow)
{
g_darkModeSupported = true;
}
}
}
}
}
void SetDarkMode(bool useDark, bool fixDarkScrollbar)
{
if (g_darkModeSupported)
{
AllowDarkModeForApp(useDark);
//_RefreshImmersiveColorPolicyState();
FlushMenuThemes();
if (fixDarkScrollbar)
{
//FixDarkScrollBar();
}
g_darkModeEnabled = ShouldAppsUseDarkMode() && !IsHighContrast();
}
}
#pragma endregion DarkMode.cpp
#pragma region UAHMenuBar
// MIT license, see LICENSE
// Copyright(c) 2021 adzm / Adam D. Walling
// processes messages related to UAH / custom menubar drawing.
// return true if handled, false to continue with normal processing in your wndproc
bool UAHDarkModeWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* lr);
// window messages related to menu bar drawing
#define WM_UAHDESTROYWINDOW 0x0090 // handled by DefWindowProc
#define WM_UAHDRAWMENU 0x0091 // lParam is UAHMENU
#define WM_UAHDRAWMENUITEM 0x0092 // lParam is UAHDRAWMENUITEM
#define WM_UAHINITMENU 0x0093 // handled by DefWindowProc
#define WM_UAHMEASUREMENUITEM 0x0094 // lParam is UAHMEASUREMENUITEM
#define WM_UAHNCPAINTMENUPOPUP 0x0095 // handled by DefWindowProc
// describes the sizes of the menu bar or menu item
typedef union tagUAHMENUITEMMETRICS
{
// cx appears to be 14 / 0xE less than rcItem's width!
// cy 0x14 seems stable, i wonder if it is 4 less than rcItem's height which is always 24 atm
struct {
DWORD cx;
DWORD cy;
} rgsizeBar[2];
struct {
DWORD cx;
DWORD cy;
} rgsizePopup[4];
} UAHMENUITEMMETRICS;
// not really used in our case but part of the other structures
typedef struct tagUAHMENUPOPUPMETRICS
{
DWORD rgcx[4];
DWORD fUpdateMaxWidths : 2; // from kernel symbols, padded to full dword
} UAHMENUPOPUPMETRICS;
// hmenu is the main window menu; hdc is the context to draw in
typedef struct tagUAHMENU
{
HMENU hmenu;
HDC hdc;
DWORD dwFlags; // no idea what these mean, in my testing it's either 0x00000a00 or sometimes 0x00000a10
} UAHMENU;
// menu items are always referred to by iPosition here
typedef struct tagUAHMENUITEM
{
int iPosition; // 0-based position of menu item in menubar
UAHMENUITEMMETRICS umim;
UAHMENUPOPUPMETRICS umpm;
} UAHMENUITEM;
// the DRAWITEMSTRUCT contains the states of the menu items, as well as
// the position index of the item in the menu, which is duplicated in
// the UAHMENUITEM's iPosition as well
typedef struct UAHDRAWMENUITEM
{
DRAWITEMSTRUCT dis; // itemID looks uninitialized
UAHMENU um;
UAHMENUITEM umi;
} UAHDRAWMENUITEM;
// the MEASUREITEMSTRUCT is intended to be filled with the size of the item
// height appears to be ignored, but width can be modified
typedef struct tagUAHMEASUREMENUITEM
{
MEASUREITEMSTRUCT mis;
UAHMENU um;
UAHMENUITEM umi;
} UAHMEASUREMENUITEM;
#pragma endregion UAHMenuBar
#pragma region UAHDarkModeWndProc
/*
* Code taken from:
* https://github.com/adzm/win32-darkmode/blob/56e617ccba1a5c7950a1e80fb5215ebb3b7f918b/win32-darkmode/win32-darkmode.cpp
* Refer to the license in the repository above
*/
static HTHEME g_menuTheme = nullptr;
// processes messages related to UAH / custom menubar drawing.
// return true if handled, false to continue with normal processing in your wndproc
bool UAHDarkModeWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* lr)
{
switch (message)
{
case WM_UAHDRAWMENU:
{
UAHMENU* pUDM = (UAHMENU*)lParam;
RECT rc = { 0 };
// get the menubar rect
{
MENUBARINFO mbi = { sizeof(mbi) };
GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi);
RECT rcWindow;
GetWindowRect(hWnd, &rcWindow);
// the rcBar is offset by the window rect
rc = mbi.rcBar;
OffsetRect(&rc, -rcWindow.left, -rcWindow.top);
rc.top -= 1;
}
if (!g_menuTheme) {
g_menuTheme = OpenThemeData(hWnd, L"Menu");
}
DrawThemeBackground(g_menuTheme, pUDM->hdc, MENU_POPUPITEM, MPI_NORMAL, &rc, nullptr);
return true;
}
case WM_UAHDRAWMENUITEM:
{
UAHDRAWMENUITEM* pUDMI = (UAHDRAWMENUITEM*)lParam;
// get the menu item string
wchar_t menuString[256] = { 0 };
MENUITEMINFO mii = { sizeof(mii), MIIM_STRING };
{
mii.dwTypeData = menuString;
mii.cch = (sizeof(menuString) / 2) - 1;
GetMenuItemInfo(pUDMI->um.hmenu, pUDMI->umi.iPosition, TRUE, &mii);
}
// get the item state for drawing
DWORD dwFlags = DT_CENTER | DT_SINGLELINE | DT_VCENTER;
int iTextStateID = 0;
int iBackgroundStateID = 0;
{
if ((pUDMI->dis.itemState & ODS_INACTIVE) | (pUDMI->dis.itemState & ODS_DEFAULT)) {
// normal display
iTextStateID = MPI_NORMAL;
iBackgroundStateID = MPI_NORMAL;
}
if (pUDMI->dis.itemState & ODS_HOTLIGHT) {
// hot tracking
iTextStateID = MPI_HOT;
iBackgroundStateID = MPI_HOT;
}
if (pUDMI->dis.itemState & ODS_SELECTED) {
// clicked -- MENU_POPUPITEM has no state for this, though MENU_BARITEM does
iTextStateID = MPI_HOT;
iBackgroundStateID = MPI_HOT;
}
if ((pUDMI->dis.itemState & ODS_GRAYED) || (pUDMI->dis.itemState & ODS_DISABLED)) {
// disabled / grey text
iTextStateID = MPI_DISABLED;
iBackgroundStateID = MPI_DISABLED;
}
if (pUDMI->dis.itemState & ODS_NOACCEL) {
dwFlags |= DT_HIDEPREFIX;
}
}
if (!g_menuTheme) {
g_menuTheme = OpenThemeData(hWnd, L"Menu");
}
DrawThemeBackground(g_menuTheme, pUDMI->um.hdc, MENU_POPUPITEM, iBackgroundStateID, &pUDMI->dis.rcItem, nullptr);
DrawThemeText(g_menuTheme, pUDMI->um.hdc, MENU_POPUPITEM, iTextStateID, menuString, mii.cch, dwFlags, 0, &pUDMI->dis.rcItem);
return true;
}
case WM_THEMECHANGED:
{
if (g_menuTheme) {
CloseThemeData(g_menuTheme);
g_menuTheme = nullptr;
}
// continue processing in main wndproc
return false;
}
default:
return false;
}
}
#pragma endregion UAHDarkModeWndProc
#pragma region drawUAHMenuNCBottomLine
/*
* Code taken from:
* https://github.com/notepad-plus-plus/notepad-plus-plus/blob/bab3573be708bb908b8080e3e2007ea78a7f1932/PowerEditor/src/NppDarkMode.cpp
* Refer to the license in the repository above
*/
void drawUAHMenuNCBottomLine(HWND hWnd)
{
MENUBARINFO mbi = { sizeof(mbi) };
if (!GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi))
{
return;
}
RECT rcClient = { 0 };
GetClientRect(hWnd, &rcClient);
MapWindowPoints(hWnd, nullptr, (POINT*)&rcClient, 2);
RECT rcWindow = { 0 };
GetWindowRect(hWnd, &rcWindow);
OffsetRect(&rcClient, -rcWindow.left, -rcWindow.top);
// the rcBar is offset by the window rect
RECT rcAnnoyingLine = rcClient;
rcAnnoyingLine.bottom = rcAnnoyingLine.top;
rcAnnoyingLine.top--;
HDC hdc = GetWindowDC(hWnd);
SetDCBrushColor(hdc, RGB(60, 60, 60));
FillRect(hdc, &rcAnnoyingLine, (HBRUSH)GetStockObject(DC_BRUSH));
ReleaseDC(hWnd, hdc);
}
#pragma endregion drawUAHMenuNCBottomLine
LRESULT CALLBACK BeefIDEWindowSubclassProc(
_In_ HWND hWnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam,
_In_ UINT_PTR uIdSubclass,
_In_ DWORD_PTR dwRefData
)
{
LRESULT lr = 0;
if (g_darkModeSupported && UAHDarkModeWndProc(hWnd, uMsg, wParam, lParam, &lr)) {
return lr;
}
switch (uMsg)
{
case WM_NCACTIVATE:
case WM_NCPAINT:
lr = DefSubclassProc(hWnd, uMsg, wParam, lParam);
drawUAHMenuNCBottomLine(hWnd);
return lr;
case WM_CTLCOLOREDIT:
SetBkColor((HDC)wParam, RGB(60, 60, 60));
SetTextColor((HDC)wParam, RGB(0xff, 0xff, 0xff));
SetDCBrushColor((HDC)wParam, RGB(60, 60, 60));
return (INT_PTR)(HBRUSH)GetStockObject(DC_BRUSH);
default:
if (uMsg == g_subclassRegisteredMsg && !wParam)
RemoveWindowSubclass(hWnd, BeefIDEWindowSubclassProc, 0);
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
void SubclassBeefIDEWindow(HWND hWnd)
{
SetWindowSubclassFromAnyThread(hWnd, BeefIDEWindowSubclassProc, 0, 0);
}
void UnsubclassBeefIDEWindow(HWND hWnd)
{
SendMessage(hWnd, g_subclassRegisteredMsg, FALSE, 0);
}
HWND BeefIDEWindowHandle;
BOOL SetDarkModeBeefIDEWindow(HWND hWnd)
{
if (BeefIDEWindowHandle)
return FALSE;
BeefIDEWindowHandle = hWnd;
SubclassBeefIDEWindow(hWnd);
AllowDarkModeForWindow(BeefIDEWindowHandle, true);
RefreshTitleBarThemeColor(BeefIDEWindowHandle);
RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
return TRUE;
}
BOOL UnsetDarkModeBeefIDEWindow()
{
if (!BeefIDEWindowHandle)
return FALSE;
HWND hWnd = BeefIDEWindowHandle;
BeefIDEWindowHandle = NULL;
UnsubclassBeefIDEWindow(hWnd);
AllowDarkModeForWindow(hWnd, false);
RefreshTitleBarThemeColor(hWnd);
RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
return TRUE;
}
HWND EditWindowHandle;
BOOL SetDarkModeEditWindow(HWND hWnd)
{
EditWindowHandle = hWnd;
SetWindowTheme(hWnd, L"DarkMode_Explorer", NULL);
return TRUE;
}
BOOL UnsetDarkModeEditWindow()
{
if (!EditWindowHandle)
return FALSE;
HWND hWnd = EditWindowHandle;
EditWindowHandle = NULL;
SetWindowTheme(hWnd, NULL, NULL);
return TRUE;
}
BOOL CALLBACK FindCurrentProcessBeefIDEWindowEnumFunc(HWND hWnd, LPARAM lParam)
{
DWORD dwProcessId = 0;
if (!GetWindowThreadProcessId(hWnd, &dwProcessId) || dwProcessId != GetCurrentProcessId())
return TRUE;
WCHAR szClassName[16];
if (GetClassName(hWnd, szClassName, ARRAYSIZE(szClassName)) == 0 || wcsicmp(szClassName, BFWindow) != 0)
return TRUE;
*(HWND*)lParam = hWnd;
return FALSE;
}
HWND FindCurrentProcessBeefIDEWindow()
{
HWND hBeefIDEWnd = NULL;
EnumWindows(FindCurrentProcessBeefIDEWindowEnumFunc, (LPARAM)&hBeefIDEWnd);
return hBeefIDEWnd;
}
using CreateWindowExW_t = decltype(&CreateWindowExW);
CreateWindowExW_t pOriginalCreateWindowExW;
HWND WINAPI CreateWindowExWHook(
DWORD dwExStyle,
LPCWSTR lpClassName,
LPCWSTR lpWindowName,
DWORD dwStyle,
int X,
int Y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam)
{
HWND hWnd = pOriginalCreateWindowExW(
dwExStyle,
lpClassName,
lpWindowName,
dwStyle,
X,
Y,
nWidth,
nHeight,
hWndParent,
hMenu,
hInstance,
lpParam
);
if (!hWnd)
return hWnd;
BOOL bTextualClassName = ((ULONG_PTR)lpClassName & ~(ULONG_PTR)0xffff) != 0;
Wh_Log(L"%X", (DWORD)(ULONG_PTR)lpClassName);
if (bTextualClassName)
Wh_Log(L"Created window of class %s", lpClassName);
else
Wh_Log(L"Created window of class atom %X", (DWORD)(ULONG_PTR)lpClassName);
if (bTextualClassName && wcsicmp(lpClassName, BFWindow) == 0)
{
Wh_Log(L"BeefIDE window created: %08X", (DWORD)(ULONG_PTR)hWnd);
SetDarkModeBeefIDEWindow(hWnd);
}
else if (BeefIDEWindowHandle && hWndParent == BeefIDEWindowHandle)
{
if (bTextualClassName && wcsicmp(lpClassName, L"Edit") == 0)
{
Wh_Log(L"Edit window created: %08X", (DWORD)(ULONG_PTR)hWnd);
SetDarkModeEditWindow(hWnd);
}
else if (bTextualClassName && wcsicmp(lpClassName, L"msctls_statusbar32") == 0)
{
Wh_Log(L"msctls_statusbar32 window created: %08X", (DWORD)(ULONG_PTR)hWnd);
// SubclassStatusBar(hWnd);
}
}
return hWnd;
}
// The mod is being initialized, load settings, hook functions, and do other
// initialization stuff if required.
BOOL Wh_ModInit() {
Wh_Log(L"Init");
InitDarkMode();
SetDarkMode(true, false);
Wh_SetFunctionHook((void*)CreateWindowExW, (void*)CreateWindowExWHook, (void**)&pOriginalCreateWindowExW);
WNDCLASS wndclass;
if (GetClassInfo(GetModuleHandle(NULL), BFWindow, &wndclass))
{
HWND hBeefIDEWnd = FindCurrentProcessBeefIDEWindow();
if (hBeefIDEWnd)
{
SetDarkModeBeefIDEWindow(hBeefIDEWnd);
HWND hEditWnd = FindWindowEx(hBeefIDEWnd, NULL, L"Edit", NULL);
if (hEditWnd)
SetDarkModeEditWindow(hEditWnd);
// HWND hStatusBarWnd = FindWindowEx(hBeefIDEWnd, NULL, L"msctls_statusbar32", NULL);
// if (hStatusBarWnd)
// SubclassStatusBar(hStatusBarWnd);
}
}
return TRUE;
}
// The mod is being unloaded, free all allocated resources.
void Wh_ModUninit() {
Wh_Log(L"Uninit");
SetDarkMode(false, false);
}
// The mod setting were changed, reload them.
void Wh_ModSettingsChanged() {
Wh_Log(L"SettingsChanged");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment