Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WallpaperQ: A Wallpaper Management Tool

0.00/5 (No votes)
7 Sep 2005 1  
A free tool to queue up and automatically change wallpaper images.

Sample Image - fullscreen.jpg

Table of Contents

  • Introduction
  • User's manual
    • Getting started
    • Browsing for images
    • Adding images to the queue
    • Changing the order, and removal of queued images
    • Setting the wallpaper's position
    • Setting the selected image as your current wallpaper
    • Full screen viewing
    • Shell notification icon
    • Program options
  • Code snippets
  • Conclusion
  • Revision history

Introduction: What is WallpaperQ?

WallpaperQ (short for Wallpaper Queue), is an application which will change your Windows wallpaper at system startup or after a configurable timer interval. The next wallpaper image is retrieved from a list or "queue" of valid image files in sequential order or randomly per the program's configuration.

I made the original version of this application a couple of years ago for my burgeoning wallpaper archive, so I'm labeling this version 2.5. The original only displayed .BMP files and the user interface was pathetic to say the least, so this is a substantial improvement.

User's manual

The application was written in VC++ 7 with MFC and it uses some GDI+ classes, so you will need to have the appropriate DLLs loaded in order to run it (gdiplus.dll, mfc70.dll, mfc70u.dll, msvcr70.dll).

Getting started

When WallpaperQ is executed for the first time, the Options dialog will popup. For more details on this dialog window, please see the Program options section below. After closing the Options dialog, the Configure window will be displayed. This is the main program window, where the wallpaper queue is setup. From this window, you can browse to your wallpaper image folder(s), preview images, add images to the queue, modify the image queue, and change how and when each wallpaper image is displayed.

Browsing for images

The first order of business, in setting up our image queue, is to find images. The Look In edit box and the Browse... button are there for this purpose. (Figure 1)

Figure 1: Browse for images or image folder

You may type in a path here or browse to a folder with valid wallpaper images (.bmp, .jpg, .gif, etc.). When a path is entered or chosen, all valid wallpaper images will be added to the images listbox automatically.

Adding images to the queue

Once you have found some images, you can preview one of them by selecting one from the Image listbox. A thumbnail of the image will then be shown in the Preview area. Screen resolution, and image size and color depth are also displayed with the preview of the selected image. (Figure 2)

To add images to the queue list, select an image or multiple images from the Image listbox and click the Queue Images button.

Figure 2: Add Images and Preview area

Changing the order, and removal of queued images

After browsing for and adding images to the queue listbox, we can rearrange or delete these images from the queue list.

Note: Images are queued to be displayed as wallpaper in the same order as they appear in the Queued Images listbox, unless the Randomize Display of Images checkbox is checked.

To rearrange the order of images, select the image to move in the Queued Image listbox and click the Arrow Up button to move the image up in the queue and the Arrow Down button to move it down in the queue. To display images randomly from the queued list, check the Randomize Display of Images checkbox.

Deletion of images from the queue is achieved via the Delete Selected and Delete All buttons. The Delete Selected button removes the selected item(s) from the Queued Images listbox, while the Delete All button removes all items from the listbox. (Figure 4)

Setting the Wallpaper's Position

You can change the "position" of the selected image(s) when it's displayed, by making a selection in the Position dropdown list box. The position of the displayed wallpaper can be one of three choices; Tiled, Center, or Stretch. Choosing Tiled, from the dropdown, will tile multiple copies of an image across the entire screen. Center will center an image on the screen. Lastly, Stretch, stretches an image to fit the size of the display. (Figure 4)

Setting the Selected Image As Your Current Wallpaper

To set the currently selected image, in the Queued Image listbox, to the current wallpaper, select an image in the list and click the Set Current button. (Figure 4)

Full Screen Viewing

If you would like to see the current wallpaper without all of the clutter of windows and icons, just click the Hide/Show Desktop Icons button (Figure 4). This action will minimize all windows and hide all of the icons on the desktop giving you a clean view of your wonderful wallpaper. To restore your icons and windows, just pull up the queue and click the Hide/Show Desktop Icons button again, or wait 2 minutes and they will be restored automatically.

Figure 3: Unobscured Viewing

Figure 4: Queued Image area

Shell notification icon

If not being run for the first time, WallpaperQ's Configuration window will remain invisible. Access to the application will be available via right-clicking the WallpaperQ shell notification (or system tray) icon.

Right-clicking the tray icon displays a context menu, with multiple options. (Figure 5) Choosing Configure Wallpaper Queue will show the main configuration window, where images can be browsed and queued. Clicking Set Wallpaper to Next Image will change the wallpaper to the next image in the queue or a random image if specified. The Options item will open the Program Options window. Clicking the About Wallpaper Queue item will display the application's About window. Finally, Exit Wallpaper Queue will completely close the application.

Figure 5: Tray Icon Context Menu

Program Options

The Program Options window is where the user can change startup and timer settings. (Figure 6)

WallpaperQ, by default, will be set to run at system startup for the logged on user. If you don't want the application to start when Windows starts, uncheck the Run at system startup checkbox. If you do want it to start with Windows, you can choose to start for all users or just the logged on user via the This User and All Users radio buttons.

If you're concerned about too many background processes running, the Exit after changing wallpaper checkbox will close the application after it runs and changes the wallpaper.

Finally, the Change wallpaper every X hours X minutes checkbox and edit boxes will change the wallpaper after a specified timer interval. Normally, the wallpaper is changed only after startup or user intervention.

Figure 6: The Program Options window

Code snippets

Starting and shutting down GDI+

To use GDI+ in our non .NET application, we need to start up GDI+ and then shut it down when we're finished.

GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;

// Initialize GDI+.

// GDI+ is used to show the thumbnail previews.

GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
...
// shutdown GdiPlus

GdiplusShutdown(gdiplusToken);

Instantiating the IActiveDesktop interface pointer

In order to use images other than just .BMPs, we need to use IActiveDesktop. Of course we need to release the interface when we're finished with it (see source code).

pIActiveDesktop = NULL;

HRESULT hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, 
    CLSCTX_INPROC_SERVER, IID_IActiveDesktop, (void**) &pIActiveDesktop);

if (FAILED(hr)) pIActiveDesktop = NULL;

Filling the Image listbox after browsing to a folder

We first need to check if IActiveDesktop is available, so we can put more image types in the ListBox. Then we find all images of the supported types.

CFileFind finder;
int iOnlyBMPs = 1;
...
// Build the search string.

if (cstrBrowsePath.GetAt(cstrBrowsePath.GetLength()-1) != '\\') 
    cstrBrowsePath += "\\";

CString cstrSearch[6] = {cstrBrowsePath + "*.bmp", cstrBrowsePath + 
    "*.jpg", cstrBrowsePath + "*.jpeg", cstrBrowsePath + "*.gif", 
    cstrBrowsePath + "*.dib", cstrBrowsePath + "*.png"};
    
// If Active Desktop is available, we can use other images besides BMPs.
if (pIActiveDesktop != NULL) 
    iOnlyBMPs = 6;

// Get all image files into the list.
for (int i=0; i < iOnlyBMPs; i++)
{
    BOOL bWorking = finder.FindFile(cstrSearch[i]);
    while (bWorking)
    {
        bWorking = finder.FindNextFile();
        m_lbBrowseList.AddString(finder.GetFilePath());
    }

    finder.Close();
}

Previewing an image with a thumbnail

I decided to use GDI+ mainly because getting a thumbnail preview of an image was so darn easy. Maintaining the aspect ratio of the image was the only part that required some thought.

// Initialize the Graphics class in GDI+.

Graphics graphics(pDC->m_hDC);
...
// Use the Image class to display a thumbnail of the image.

Image image(T2CW(szBuf));
...
// Determine the appropriate size of the thumbnail preview

// given the image size ratio and the preview window size ratio.

uiWidth = image.GetWidth();
uiHeight = image.GetHeight();
dRatio = ((double)uiWidth)/((double)uiHeight);

// If the width is larger than the height of the image, 

// set the width of the thumbnail to the width of the preview area

// and calculate the thumbnail height by using the ratios.

// If the height is larger than the width of the image, 

// set the height of the thumbnail to the height of the preview area

// and calculate the thumbnail width by using the ratios.

if (uiWidth > uiHeight)
{
    thumbWidth = rect.right - rect.left;
    thumbHeight = (UINT)(thumbWidth/dRatio);
    if (thumbHeight == 0) thumbHeight = 1;
    if (thumbHeight > (UINT)(rect.bottom - rect.top)) 
        thumbHeight = rect.bottom - rect.top;

    // Adjust things to make the preview not paint over the control border.

    iAdjTop = 1 + ((rect.bottom - rect.top)/2) - (thumbHeight/2);
    iAdjLeft = 1;
}
else
{
    thumbHeight = rect.bottom - rect.top;
    thumbWidth = (UINT)(uiWidth*thumbHeight/uiHeight);

    if (thumbWidth == 0) thumbWidth = 1;
    if (thumbWidth > (UINT)(rect.right - rect.left)) 
        thumbWidth = rect.right - rect.left;

    // Adjust things to make the preview not paint over the control border.

    iAdjTop = 1;
    iAdjLeft = 1 + ((rect.right - rect.left)/2) - (thumbWidth/2);
}

// Get the thumbnail and display it in the preview control.

Image* pThumbnail = image.GetThumbnailImage(thumbWidth, 
                                thumbHeight, NULL, NULL);
graphics.DrawImage(pThumbnail, iAdjLeft, iAdjTop, 
    pThumbnail->GetWidth(), pThumbnail->GetHeight());
delete pThumbnail;

Changing the wallpaper image and position

If IActiveDesktop is not available, we change values in the registry to set the position and then use the SystemParametersInfo API function to actually change the wallpaper image. If IActiveDesktop is available, we use methods from it to do the dirty work. The SetDesktopItemOptions method is used to make sure ActiveDesktop is enabled, otherwise the settings and image would not change. SetWallpaperOptions is used to set the position, while SetWallpaper sets the wallpaper image. After we set the position and wallpaper, we also need to call the ApplyChanges method to make the changes now.

// If Active Desktop is not available, 

//use the SystemParametersInfo function.

if (pIActiveDesktop == NULL)
{
    if (iPosition == 0)
    {
        // Tiled

        cstrTileWallpaper = "1";
        cstrWallpaperStyle = "1";
    }
    else if (iPosition == 1)
    {
        // Center

        cstrTileWallpaper = "0";
        cstrWallpaperStyle = "1";
    }
    else
    {
        // Stretch

        cstrTileWallpaper = "0";
        cstrWallpaperStyle = "2";
    }

    // Set registry values for the wallpaper position.

    CRegistry::SetRegString("Control Panel\\Desktop", 
                "TileWallpaper", cstrTileWallpaper);
    CRegistry::SetRegString("Control Panel\\Desktop", 
                "WallpaperStyle", cstrWallpaperStyle);

    // Change the wallpaper.

    SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*)szBuf, 
        SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);    
}
else
{
    WALLPAPEROPT wpOptions;
    COMPONENTSOPT compOptions;

    compOptions.dwSize = sizeof(COMPONENTSOPT);
    compOptions.fActiveDesktop = TRUE;
    compOptions.fEnableComponents = TRUE;

    pIActiveDesktop->SetDesktopItemOptions(&compOptions, 0);

    // Set the wallpaper position.

    wpOptions.dwSize = sizeof(WALLPAPEROPT);
    if (iPosition == 0)
        wpOptions.dwStyle = WPSTYLE_TILE;
    else if (iPosition == 1)
        wpOptions.dwStyle = WPSTYLE_CENTER;
    else
        wpOptions.dwStyle = WPSTYLE_STRETCH;

    pIActiveDesktop->SetWallpaperOptions(&wpOptions, 0);

    // Set the wallpaper image.

    pIActiveDesktop->SetWallpaper(T2CW(szBuf), 0);

    // Apply all changes.

    pIActiveDesktop->ApplyChanges(AD_APPLY_ALL);
}

Hiding Icons and Minimizing Windows

To minimize all windows I invoke the Shell's MinimizeAll method, and to restore the windows I invoke UndoMinimizeALL. See the MinimizeAllWindows method in the source code.

Once all windows are iconic, we hide the icons by finding the proper window and making it hidden. You can use the Spy++ utility to find the FolderView window on the Desktop and get its class name for the FindWindowEx method.

// hide desktop icons

CWnd* pProgMan = FindWindowEx(NULL, NULL, "ProgMan", "Program Manager");
CWnd* pSHELLDLL_DefView = FindWindowEx(pProgMan->GetSafeHwnd(), 
                                 NULL, "SHELLDLL_DefView", "");
CWnd* pFolderView = FindWindowEx(pSHELLDLL_DefView->GetSafeHwnd(), 
                             NULL, "SysListView32", "FolderView");
pFolderView->ShowWindow(SW_HIDE);
...
// show desktop icons

pFolderView->ShowWindow(SW_SHOW);

Conclusion

If you find any bugs, or if you have some enhancement suggestions, just post a message on this page or feel free to modify the code yourself. By the way, I would appreciate and enjoy hearing about them. I hope you enjoy WallpaperQ!

Revision history

This is not the first version of WallpaperQ. Version 1.0 had a terrible GUI not meant for public use and it only supported .BMP images. Therefore, I have dubbed this Version 2.00.1 and with your testing and suggestions, there will hopefully be some enhancements to come.

  • Version 2.00.2 - Now deleting the thumbnail pointer which should help with the memory usage.
  • Version 2.50 - Several enhancements:
    • If an image no longer exists it won't crash now.
    • Clicking Cancel will not change wallpaper.
    • Double-clicking the tray icon will open the configuration window.
    • The last path will be restored if you click Cancel on the image path browse window.
    • The default Position is now Stretch.
    • It will attempt to determine the proper Position based on image size.
    • Set selected image as current wallpaper functionality added.
    • Hide/Show Desktop icons and minimize/restore all windows functionality added.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here