0

I'm having an issue where if I get ProgMan to create a WorkerW window behind the desktop icons (as described by https://stackoverflow.com/a/56132585/5923516), it allows me to draw to it the first time, but if I stop it and then try and run it again, it fails to draw. By 'fails to draw', I mean that I don't see any errors, but it just doesn't do anything. I've also tried to debug it and none of the effected values change (i.e. the wallpaper_hwnd variable points to the same place, and none of the SDL functions return error values) I've verified this behaviour on both Windows 10 and 11, both using different video drivers. The only way I've found to fix this is to log out then log back in, which doesn't really help.

Once exited I also noticed that the background instantly changes back to the wallpaper picture/colour. But I don't know if that information is useful.

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <shellapi.h>

// Can also be <SDL.h> depending on the install of SDL
#include <SDL2/SDL.h>

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
    HWND ShellHandle = FindWindowEx(hwnd, NULL, "SHELLDLL_DefView", NULL);
    HWND *ret = (HWND *) lParam;

    if (ShellHandle) {
        *ret = FindWindowEx(NULL, hwnd, "WorkerW", NULL);
    }
    return true;
}

int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int ShowCmd) {
    // Get the ProgMan Window
    HWND progman = FindWindow("ProgMan", NULL);
    
    // Get ProgMan to create a WorkerW
    SendMessageTimeout(progman, 0x052C, 0, 0, SMTO_NORMAL, 1000, nullptr);
    
    // Find the WorkerW that was spawned
    HWND wallpaper_hwnd = nullptr;
    EnumWindows(EnumWindowsProc, (LPARAM) &wallpaper_hwnd);

    // Init SDL2
    SDL_Init(SDL_INIT_VIDEO);

    // Create an SDL Window from this
    SDL_Window* sdl_window = SDL_CreateWindowFrom((void*)wallpaper_hwnd);

    // Create SDL Renderer from the SDL Window
    SDL_Renderer* renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

    // Clear the window as a test
    SDL_RenderClear(renderer);
    SDL_RenderPresent(renderer);

    // Sleep for 1 second so that the change is actually visible
    Sleep(1000);

    // Clean up
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(sdl_window);

    SDL_Quit();

    // In my testing this doesn't fix it:
    // DestroyWindow(wallpaper_hwnd);

    return 0;
}

If anyone can work out why I'm getting these issues then I would greatly appreciate it.

EDIT:

After messing around a bit, I've found that wintabbing makes it work again. This still isn't a very good solution, however.

Bob Willett
  • 26
  • 1
  • 5
  • Implementation details are just that. The system makes no promises as to what your code should do. Any observable behavior is possible. If you want a robust implementation, use the stable API. This may mean that what you're trying to do simply isn't possible. Speaking of which: What *problem* are you trying to solve? – IInspectable Dec 03 '21 at 10:35
  • I'm trying to draw images to the background, somewhat like wallpaper engine or xwallpaper, just instead using GLSL shaders instead – Bob Willett Dec 03 '21 at 10:46
  • The code I currently have is https://github.com/ProtoByter/WallShader – Bob Willett Dec 03 '21 at 10:47
  • Also I'm confused by what you mean by a stable API, since both SDL 2 and the windows API should be stable – Bob Willett Dec 03 '21 at 10:48
  • There is no supported interface to do that. Previously, that was possible using [Active Desktop](https://en.wikipedia.org/wiki/Active_Desktop) but that got phased out with Windows Vista. – IInspectable Dec 03 '21 at 10:49
  • Well windows does what I'm doing itself when it wants to change the wallpaper (for the fade) so it should be possible – Bob Willett Dec 03 '21 at 10:53
  • `"ProgMan"`, `"WorkerW"`, and `"SHELLDLL_DefView"` are implementation details. Neither their names nor their topology are part of the public API. [`IDesktopWallpaper`](https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-idesktopwallpaper) is the public API for interacting with the desktop wallpaper. Trying to do what it doesn't offer will have you rely on implementation details. Doing so requires intimate familiarity with the system, and even then it's simply not supported. – IInspectable Dec 03 '21 at 10:53
  • @BobWillett "*Well windows does what I'm doing itself when it wants to change the wallpaper (for the fade) so it should be possible*" - just because the OS can do something doesn't mean user code can do the same thing. The OS has lots of private access to things we don't have access to. – Remy Lebeau Dec 03 '21 at 16:31
  • This isn't a particular property of the OS either. You'd run into the exact same issues if you tried to render onto the GUI of any given program. This would require coöperation of the program in question. Windows' Shell doesn't offer that, and most programs don't, either. – IInspectable Dec 04 '21 at 08:00

0 Answers0