ramensoftware / windhawk

The customization marketplace for Windows programs: https://windhawk.net/
https://windhawk.net
GNU General Public License v3.0
2.19k stars 70 forks source link

Allow Multiple Instances or Add Backwards Compatibility #139

Closed legacy1477 closed 11 months ago

legacy1477 commented 11 months ago

An issue already showed up with some scripts breaking in newer versions of Windhawk.

An easy solution would be to allow multiple versions to run at the same time. Or add a line in the source code indicating Windhawk should emulate an older version.

For example:

// ==WindhawkMod==
// @id              new-mod
// @name            Your Awesome Mod
// @description     The best mod ever that does great things
// @version         0.1
// @author          You
// @compatibility         1.3.1 
m417z commented 11 months ago

That's not something that can be easily done. Ideally, such breakage should be very rare, and shouldn't affect mods in the official repository. Ideally it would be a good idea to verify that all mods compile before releasing a new version, but I didn't have the time to implement such a check yet.

What breakage did you encounter? Please post the code of the mod if possible.

legacy1477 commented 11 months ago

That's not something that can be easily done. Ideally, such breakage should be very rare, and shouldn't affect mods in the official repository. Ideally it would be a good idea to verify that all mods compile before releasing a new version, but I didn't have the time to implement such a check yet.

What breakage did you encounter? Please post the code of the mod if possible.

// ==WindhawkMod==
// @id              classic-conhost
// @name            Classic Conhost
// @description     Forces classic theme and optionally client edge on console windows
// @version         1.0.0
// @author          aubymori
// @github          https://github.com/aubymori
// @include         *
// @compilerOptions -luser32 -ldwmapi -luxtheme
// ==/WindhawkMod==

// ==WindhawkModReadme==
/*
# Classic Conhost

This mod will apply classic theme and optionally client edge to console windows.

**Before**:

![Before](https://raw.githubusercontent.com/aubymori/images/main/classic-conhost-before.png)

**After**:

![After](https://raw.githubusercontent.com/aubymori/images/main/classic-conhost-after.png)
*/
// ==/WindhawkModReadme==

// ==WindhawkModSettings==
/*
- classic: true
  $name: Classic theme
  $description: Apply classic theme to console windows. Disable this if you use classic theme system-wide.
- clientedge: true
  $name: Client edge (Classic theme only)
  $description: Apply a client edge to console windows
*/
// ==/WindhawkModSettings==

#include <windows.h>
#include <processthreadsapi.h>
#include <uxtheme.h>
#include <dwmapi.h>

HANDLE g_hObserverThread;

struct {
    bool classic;
    bool clientedge;
} settings;

BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
    WCHAR szClass[MAX_PATH];
    int   nStatus = GetClassNameW(hWnd, szClass, MAX_PATH);
    BOOL  bIsValidString = (((ULONG_PTR)szClass & ~(ULONG_PTR)0xffff) != 0);

    if (nStatus && bIsValidString && !wcscmp(szClass, L"ConsoleWindowClass"))
    {
        if (settings.classic)
        {
            /* Set window theme */
            SetWindowTheme(hWnd, L" ", L" ");
            SendMessage(hWnd, WM_THEMECHANGED, NULL, NULL);

            /* Disable DWM NC frames */
            DWORD dwPol = DWMNCRP_DISABLED;
            DwmSetWindowAttribute(
                hWnd,
                DWMWA_NCRENDERING_POLICY,
                &dwPol,
                sizeof(DWORD)
            );
        }

        if (settings.clientedge)
        {
            DWORD dwExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
            RECT  rcWnd;
            GetWindowRect(hWnd, &rcWnd);

            if ((dwExStyle & WS_EX_CLIENTEDGE) != WS_EX_CLIENTEDGE)
            {
                SetWindowLongPtrW(
                    hWnd,
                    GWL_EXSTYLE,
                    dwExStyle | WS_EX_CLIENTEDGE
                );

                /* Resize for client edge */
                SetWindowPos(
                    hWnd,
                    NULL,
                    0, 0,
                    rcWnd.right - rcWnd.left + 4,
                    rcWnd.bottom - rcWnd.top + 4,
                    SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE
                );
            }
        }
    }

    return TRUE;
}

DWORD CALLBACK ObserverThreadProc(HANDLE handle)
{
    HDESK curDesktop = GetThreadDesktop(GetCurrentThreadId());

    for (int i = 0; i < 2; i++)
    {
        EnumDesktopWindows(curDesktop, EnumWindowsProc, NULL);
        Sleep(1);
    }

    return 0;
}

void LoadSettings(void)
{
    settings.classic = Wh_GetIntSetting(L"classic");
    settings.clientedge = Wh_GetIntSetting(L"clientedge");
}

BOOL Wh_ModInit(void)
{
    LoadSettings();

    if (settings.classic)
    {
        WCHAR szPath[MAX_PATH], *pBackslash = NULL;
        if (GetModuleFileNameW(NULL, szPath, MAX_PATH))
        {
            LPWSTR szPathL = wcslwr(szPath);
            pBackslash = wcsrchr(szPathL, L'\\');
            if (pBackslash && !wcscmp(pBackslash, L"\\conhost.exe"))
            {
                SetThemeAppProperties(STAP_ALLOW_NONCLIENT);
            }
        }
    }

    g_hObserverThread = CreateThread(NULL, NULL, ObserverThreadProc, NULL, NULL, NULL);
    SetPriorityClass(g_hObserverThread, REALTIME_PRIORITY_CLASS);
    SetThreadPriority(g_hObserverThread, THREAD_PRIORITY_TIME_CRITICAL);

    return TRUE;
}

void Wh_ModSettingsChanged(void)
{
    LoadSettings();
}

Example of this one not working can be found here: https://github.com/ramensoftware/windhawk-mods/issues/422 I did copy over old .h scripts to the new compiler include folder of Windhawk and tried compiling with them and while I did not encounter issues compiling the mod behaved the same way.

m417z commented 11 months ago

I tried to compile this mod with the latest Windhawk version and it worked. Perhaps the problem was caused by copying Windhawk header files around. Once you start doing those kinds of things, nothing is guaranteed to work.

I'm closing this issue since there seems to be no problem, and since I'm not planning to implement the "old version mode" suggestion.

If you encounter mods that worked with an older version but no longer compile with the latest, unmodified Windhawk, please let me know.

legacy1477 commented 11 months ago

I tried to compile this mod with the latest Windhawk version and it worked. Perhaps the problem was caused by copying Windhawk header files around. Once you start doing those kinds of things, nothing is guaranteed to work.

I'm closing this issue since there seems to be no problem, and since I'm not planning to implement the "old version mode" suggestion.

If you encounter mods that worked with an older version but no longer compile with the latest, unmodified Windhawk, please let me know.

The problem isn't about compiling it's that on version v1.3.1 it makes CMD/conhost classic themed without issue on current version it does the same, but CMD/conhost instantly reverts when interacted with. Can you please investigate this behavior or tell anyone looking for a way to run multiple versions how to do so to get around issues like this?

m417z commented 11 months ago

I'm not using a classic theme so I'm not sure how to test it. @aubymori any idea? I don't see a reason for it to behave differently in v1.3.1 and v1.4.1.

aubymori commented 11 months ago

Ah, I remember I found what causes this but I forgot to do anything about it. I'll push an update shortly.

m417z commented 11 months ago

Thanks @aubymori

@legacy1477 from the updated description:

IMPORTANT: READ!

Windhawk and this mod need to inject into conhost.exe for this mod to work properly. Please navigate to Windhawk's Settings, Advanced settings, More advanced settings, and make sure that conhost.exe is in the Process inclusion list.

conhost.exe is marked as a system process, and Windhawk v1.4.1 doesn’t inject code into it by default. It’s tricky to find the right balance between safety and functionality, I’ll keep gathering user feedback and will adjust Windhawk accordingly.