1

For many years now, I've had a program that runs every night that generates an image that I use as my desktop background.

In the various flavors of Linux I've run, simply replacing the image file I had set as the desktop background would cause the desktop to refresh its background to use the new image.

In the various flavors of Windows I've run, I've always had to open up the display settings, change the background to a different image, and then change it back to the original (new) image, in order to get the background to change.

This is still true in Windows 10.

Is anyone aware of a way of getting Windows to automatically recognize when the background image file has changed, and to update the desktop background to reflect the change, without having to manually make the change in the GUI?

1
  • You can set the desktop image by editing the registry and refreshing the desktop. Windows won't detect it, this requires a third-party application, and for you to watch for when the file changes.
    – Ramhound
    Mar 2, 2016 at 17:55

1 Answer 1

0

Windows desktop background are always Bitmaps (BMP). When you set the desktop image via the GUI it converts your image to a BMP before applying it.

If your existing software generates a BMP then simply using something like RUNDLL32.EXE USER32.DLL,UpdatePerUserSystemParameters 1, True as presented in this SU question:

How to force Windows desktop background to update or refresh

will probably work to update the desktop after the image had been modified.

But most stuff doesn't generate BMPs, it's usually JPG or PNG these days, so this method doesn't work.

So, here's a PowerShell script that will:

  1. Create a new bitmap to be set as the desktop background ($activeBackgroundBMP).
  2. Check if the last written timestamp of the file to be monitored ($fileToCheck) has changed since last check. And if so...
  3. Load your image that gets updated by your software ($fileToCheck). This can be BMP, GIF, EXIF, JPG, PNG or TIFF.
  4. Save it to the BMP ($activeBackgroundBMP).
  5. Set the BMP as your desktop background, and make it active.
  6. Loop endlessly (until you hit Ctrl-C or end the Powershell session).

To use it:

  1. Set $fileToCheck to the path and file name of the file that your software updates.
  2. Set $activeBackgroundBMP to the path and file name that you want the BMP (used as the wallpaper) saved as.
  3. Run PowerShell "as administrator"
  4. Run the script and it should create the BMP file you specified in $activeBackgroundBMP (if it doesn't exist already), and then start looping to check for changes to $fileToCheck (every 15 seconds by default).
  5. Set your Desktop background image to the BMP.

While it's running, when $fileToCheck's modification timestamp changes, it should update the desktop background.

If wanted, you should be able to create a Scheduled Task to start the script "As Administrator" when you user logs in...

Here's the script:

# Initalize last checked "timestamp" holder.
$lastCheck = 0

# Set file paths.
$fileToCheck = "c:\temp\back.jpg"
$activeBackgroundBMP = "c:\temp\dtback.bmp"

# Load required assemblies and get object reference for System.Drawing.
$ret = [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms");

# Setup definitions so we can use User32.dll's SystemParametersInfo's SPI_SETDESKWALLPAPER.
# We only want to add the type definition of "params" if the "params" class hasn't been previously created in this PS session.
if (-not ([System.Management.Automation.PSTypeName]'Params').Type) {
    Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;

public class Params
{
    [DllImport("User32.dll",CharSet=CharSet.Unicode)]
    public static extern int SystemParametersInfo (Int32 uAction,
                                                   Int32 uParam,
                                                   String lpvParam,
                                                   Int32 fuWinIni);
}
"@
}

# Setup some constants to be used with User32.dll's SystemParametersInfo.
$SPI_SETDESKWALLPAPER = 0x0014
$UpdateIniFile = 0x01
$SendChangeEvent = 0x02
$fWinIni = $UpdateIniFile -bor $SendChangeEvent

# If the target BMP doesn't exist, create a new one.
if (-Not (Test-Path $activeBackgroundBMP)) {
    # Create a new 1x1 bitmap, and save it.
    $ret = (new-object System.Drawing.Bitmap(1,1)).Save($activeBackgroundBMP,"BMP")
    Write-Host "New BMP created ($activeBackgroundBMP)."
}

# Check if file exists before monitoring.
if (Test-Path $fileToCheck) {
    # Loop endlessly (hit Ctrl-C to break).
    while ($true) {
        # Get the last write timestamp from file.
        $lastWrite = (Get-Item $fileToCheck).LastWriteTime

        # If it's different than the Last Check time...
        if ($lastWrite -ne $lastCheck) {
            # Load the updated background image into a BMP, and save it as the target BMP.
            $img = new-object System.Drawing.Bitmap($fileToCheck)
            $img.Save($activeBackgroundBMP,"BMP")

            # Dispose of the System.Drawing object, to release the $fileToCheck file (so it can be overwritten by other processes).
            $img.Dispose()
            $img = $null

            # Refresh desktop background with the updated BMP image.
            $ret = [Params]::SystemParametersInfo($SPI_SETDESKWALLPAPER, 0, $activeBackgroundBMP, $fWinIni)

            # Update Last Check timestamp to match file's current timestamp.
            $lastCheck = $lastWrite

            Write-Host "Refeshed."
        }

        # Pause 15 seconds before looping back.
        Start-Sleep -s 15
    }
} else {
    # File doesn't exist.
    Write-Host "$fileToCheck not found, aborting."
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .