winapilistviewsyslistview32

How to get bitmap data from SysListView32?


I want to get bitmap data of windows desktop wallpaper. And, I want to draw some text directly to the bitmap.

First, I tried getting bitmap data by following code.

#include <windows.h>
#include <Commctrl.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev,
                   LPSTR cmdLine, int showCmd)
{
    CoInitialize(NULL);

    // find Progman
    HWND hProgman = FindWindow("Progman", "Program Manager");

    // find DefView
    HWND hDefView = FindWindowEx(hProgman, NULL, "SHELLDLL_DefView",  NULL);

    // find SysListView
    HWND hListView = FindWindowEx(hDefView, NULL, "SysListView32", NULL);

    char filename[512] = {0};

    LVBKIMAGE lvbki;
    lvbki.ulFlags = LVBKIF_SOURCE_HBITMAP;
    lvbki.hbm = NULL;
    lvbki.pszImage = filename;
    lvbki.cchImageMax = 512;
    lvbki.xOffsetPercent = 0;
    lvbki.yOffsetPercent = 0;

    int ret = ListView_GetBkImage(hListView, &lvbki);

    if (ret == 0) {
        MessageBox(NULL, TEXT("GetBkImage failed!"), TEXT("err"), 0);
        return -1;
    }
if (lvbki.hbm == NULL){
    MessageBox(NULL, TEXT("hbm is NULL"), TEXT("err"), 0);
    return -1;
}

    MessageBox(NULL, TEXT("FINISHED"), TEXT("msg"), 0);

    CoUninitialize();

    return 0;
}

This code's result is "hbm is NULL". It is wrong code?

My question is how to get bitmap data that displayed as desktop wallpaper on SysListView32? And, is it possible?

regards.


Solution

  • To draw directly on the desktop, you don't need to get the desktop bitmap data, but the desktop device context (DC).

    Instead of using FindWindow('SysListView32', nil); (the class name might be changed in the future), you should use GetDesktopWindow() to retrieve a handle to the desktop window, then use GetDC() to retrieve the device context (DC) of the desktop window.

    You can do text drawing using TextOut(), DrawText(), or DrawTextEx().

    Finally, call ReleaseDC() to release the desktop DC, freeing it for use by other applications.

    For example:

      deskhwnd := GetDesktopWindow();
      deskhdc := GetDC(deskhwnd);
    
      // Here code where you draw text to the desktop
    
      ReleaseDC(deskhwnd, deskhdc);
    

    However, if you really need to get the desktop bitmap data (wallpaper) for other purpose, read the value of Wallpaper in HKCU\Control Panel\Desktop. The Wallpaper value specifies the name of the file in which the bitmap for the screen background is stored. In Windows Vista and later, the wallpaper can be either BMP or JPG file, so don't use LoadImage() API function to load the wallpaper, you should use CImage or GDI+ instead, supposing you use VC++.

    Note

    @Remy Lebeau caught a flaw in my explanation about getting the wallpaper (see his comment below). Yes, I agree that we shouldn't rely on registry value if there is an API function for doing the same purpose.