darclander / starBackground

A self-made wallpaper engine which turns your windows wallpaper into a moving background.
GNU General Public License v3.0
20 stars 4 forks source link

Error retrieving HWND #7

Open darclander opened 3 years ago

darclander commented 3 years ago

For some versions of windows (incorrectly installed or non-purchased versions) it seems like the function get_wallpaper_window() does not return a correct HWND to the windows wallpaper but instead returns 0.

https://github.com/darclander/starBackground/blob/main/src/ui.cpp

HWND get_wallpaper_window() {
        // Fetch the Progman window
        HWND progman = FindWindow("ProgMan", NULL);
        // Send 0x052C to Progman. This message directs Progman to spawn a 
        // WorkerW behind the desktop icons. If it is already there, nothing 
        // happens.
        SendMessageTimeout(progman, 0x052C, 0, 0, SMTO_NORMAL, 1000, nullptr);
        // We enumerate all Windows, until we find one, that has the SHELLDLL_DefView 
        // as a child. 
        // If we found that window, we take its next sibling and assign it to workerw.
        HWND wallpaper_hwnd = nullptr;
        EnumWindows(EnumWindowsProc, (LPARAM)&wallpaper_hwnd);
        // Return the handle you're looking for.
        return wallpaper_hwnd;
}

Any solutions for this would be greatly appreciated.

MirzaBeig commented 5 months ago

Spy++ reveals the layouts/differences across machines. Try something like this:


// See if WorkerW (class) is a child of program manager ('progman').

IntPtr workerW = Win32.FindWindowEx(GetProgramManagerWindowHandle(), IntPtr.Zero, "WorkerW", null);

// If that doesn't work, try searching alternative layout.

if (workerW == IntPtr.Zero)
{
    // Enumerate top-level windows until finding SHELLDLL_DefView as child. 

    Win32.EnumWindows(new Win32.EnumWindowsProc((topHandle, topParamHandle) =>
    {
        IntPtr SHELLDLL_DefView = Win32.FindWindowEx(topHandle, IntPtr.Zero, "SHELLDLL_DefView", null);

        if (SHELLDLL_DefView != IntPtr.Zero)
        {
            // If found, take next sibling as workerW.
            // > Gets the WorkerW Window after the current one.

            workerW = Win32.FindWindowEx(IntPtr.Zero, topHandle, "WorkerW", null);
        }

        return true;

    }), IntPtr.Zero);
}

It should be found now, if it exists. You can SetParent to this handle to get live wallpapers.

darclander commented 4 months ago

@MirzaBeig wow thank you very much! I had in mind a similar solution but sadly I have been offline for too long to even attempt to solve this... :D I will see if I can implement your suggestion soon!

All the best!