Obtaining information about the user’s wallpaper on multiple monitors

Today we're going to dump information about the user's wallpaper settings on multiple monitors.

The idea is simple. You use the IDesktop­Wallpaper interface on the Desktop­Wallpaper object to get information about the desktop wallpaper. It will tell you the wallpaper positioning information, whether a single image is being used for all monitors, where those monitors are, and which image is on which monitor.

#define UNICODE
#define _UNICODE
#define STRICT
#include <windows.h>
#include <shlobj.h>
#include <atlbase.h>
#include <atlalloc.h>
#include <stdio.h> // horrors! mixing C and C++!

int __cdecl wmain(int, wchar_t **)
 CCoInitialize init;

 // Create the DesktopWallpaper object
 CComPtr<IDesktopWallpaper> spdw;
 CoCreateInstance(CLSID_DesktopWallpaper, nullptr, CLSCTX_ALL,

 // See if there is a single wallpaper on all monitors.
 CComHeapPtr<wchar_t> spszCommonWallpaper;
 HRESULT hr = spdw->GetWallpaper(nullptr, &spszCommonWallpaper);
 switch (hr) {
 case S_OK:
  printf("Same wallpaper on all monitors: %ls\n",
         static_cast<wchar_t *>(spszCommonWallpaper));
 case S_FALSE:
  printf("Different wallpaper on each monitor\n");
  printf("Mysterious error: 0x%08x\n", hr);

 // Get the number of monitors,
 UINT count;
 printf("There are %d monitors\n", count);

 // Print information about each monitor.
 for (UINT i = 0; i < count; i++) {
  // Get the device path for the monitor.
  CComHeapPtr<wchar_t> spszId;
  spdw->GetMonitorDevicePathAt(i, &spszId);
  printf("path[%d] = %ls\n",
         i, static_cast<wchar_t *>(spszId));

  // Get the monitor location.
  RECT rc;
  spdw->GetMonitorRECT(spszId, &rc);
  printf("rect = (%d, %d, %d, %d)\n",
         rc.left, rc.top, rc.bottom, rc.right);

  // Get the wallpaper on that monitor.
  CComHeapPtr<wchar_t> spszWallpaper;
  hr = spdw->GetWallpaper(spszId, &spszWallpaper);
  printf("image = %ls\n",
         static_cast<wchar_t *>(spszWallpaper));

 return 0;

The program proceeds in a few basic steps.

We create the Desktop­Wallpaper object. That object will give us the answers to our questions.

Our first question is, "Is the same wallpaper being shown on all monitors?" To determine that, we call IDesktop­Wallpaper::Get­Wallpaper and specify nullptr as the monitor ID. The call succeeds with S_OK if the same wallpaper is shown on all monitors (in which case the shared wallpaper is returned). It succeeds with S_FALSE if each monitor has a different wallpaper.

To get information about the wallpaper on each monitor, we iterate through them, first asking for the monitor device path, since that is how the Desktop­Wallpaper object identifies monitors. For each monitor, we ask for its location and the wallpaper for that monitor. Note that if the monitor is not displaying a wallpaper at all, the Get­Wallpaper method succeeds but returns an empty string.

And that's it. You can juice up this program by asking for wallpaper positioning information, and if you are feeling really adventuresome, you can use the Set­Wallpaper method to change the wallpaper.

Comments (11)
  1. Crescens2k says:

    I would assume that if each monitor is set to display a part of a larger wallpaper then it would return S_OK to the call to IDesktopWallpaper::GetWallpaper with nullptr as the monitor ID?

  2. Ancient_Hacker says:

    What happens if there are no monitors?

    What happens if a monitor goes away during this loop?    What happens if a monitor gets added during this operation?   What happens if something horrible, like the Catalyst control center, is slowly munging with the installation?

  3. SimonRev says:

    To take a stab in the dark, I bet Windows 8 wallpaper span mode internally works the same as wallpaper spanning utilities did on Win 7 and earlier — simply create a giant image the size of the desktop bounding rectangle then use the legacy Tile mode

  4. Joshua says:

    @Ancient_Hacker: No monitors — Windows pretends there is one. No video cards — I'm pretty sure BLUESCREEN when trying to display the boot animation.

  5. @Ancient says:

    There is always no error checking in Raymond little programs. That's not the point of them.

    Besides that looking at the MSDN documentation for GetMonitorDevicePathAt and GetWallpaper will answer some of your questions.

  6. Adam Rosenfield says:

    If Windows bluescreens and there's no monitor around to show it, did it really bluescreen?

  7. > you can use the Set­Wallpaper method to change the wallpaper

    Like this: blogs.msdn.com/…/command-line-app-to-set-the-desktop-wallpaper.aspx

  8. immibis says:

    > #include <stdio.h> // horrors! mixing C and C++!

    My pet peeve is people complaining about things like this.

  9. Neil says:

    What's great fun is when Remote Desktop tries and fails to turn your wallpaper off.

    I think most annoying is those PCs that had OEM branding on the logon screen, as that wasn't affected by the remote wallpaper setting.

    The other time I noticed was when remotely assisting someone with automatically changing wallpaper. Although remote assistance initially disabled the wallpaper, it was restored at the next automatic changeover interval. (Fortunately that was over a faster connection so it wasn't a problem.)

  10. Jon says:

    The only downside to this new API is that it sometimes doesn't use the fade transition when applying the wallpaper change. Sometimes it does, sometimes it doesn't, which means (for us anyway) we can't use it or our users will complain.

Comments are closed.