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;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
...
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;
...
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.
Graphics graphics(pDC->m_hDC);
...
Image image(T2CW(szBuf));
...
uiWidth = image.GetWidth();
uiHeight = image.GetHeight();
dRatio = ((double)uiWidth)/((double)uiHeight);
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;
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;
iAdjTop = 1;
iAdjLeft = 1 + ((rect.right - rect.left)/2) - (thumbWidth/2);
}
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 (pIActiveDesktop == NULL)
{
if (iPosition == 0)
{
cstrTileWallpaper = "1";
cstrWallpaperStyle = "1";
}
else if (iPosition == 1)
{
cstrTileWallpaper = "0";
cstrWallpaperStyle = "1";
}
else
{
cstrTileWallpaper = "0";
cstrWallpaperStyle = "2";
}
CRegistry::SetRegString("Control Panel\\Desktop",
"TileWallpaper", cstrTileWallpaper);
CRegistry::SetRegString("Control Panel\\Desktop",
"WallpaperStyle", cstrWallpaperStyle);
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);
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);
pIActiveDesktop->SetWallpaper(T2CW(szBuf), 0);
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.
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);
...
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.