3

I use the solution provided in this post to change the Windows desktop wallpaper from Python

In particular here is the code sample

import ctypes
import os
image_file = "myimage.jpg"
print("Setting the wallpaper")
SPI_SETDESKWALLPAPER = 20 
ctypes.windll.user32.SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0,  os.path.abspath(image_file) , 0)

The problem is that the change is non persistent, in the sense that the desktop wallpaper gets reset whenever I restart my PC. How can I persistently change the Windows desktop wallpaper from Python?

I use python 3.5

robertspierre
  • 3,218
  • 2
  • 31
  • 46
  • 1
    It's not your immediate problem, but please use `user32 = ctypes.WinDLL('user32', use_last_error=True)` instead of `ctypes.windll.user32`. Check for success and if not `raise ctypes.WinError(ctypes.get_last_error())`, so that the caller can handle the exception instead of blindly pretending that everything is fine. – Eryk Sun Jun 07 '17 at 07:02
  • As to the immediate problem, you should be able to solve that in a few seconds by reading the docs for the `fWinIni` parameter of [`SystemParametersInfo`](https://msdn.microsoft.com/en-us/library/ms724947). – Eryk Sun Jun 07 '17 at 07:06
  • @eryksun you are right, but where to I find the value of SPIF_UPDATEINIFILE? The documentation (https://msdn.microsoft.com/en-us/library/ms724947) does not provide it, while it provides the value of SPI_SETDESKWALLPAPER . In `winuser.h` it is defined as equal to 1. Is it correct to assume that this value will never change in future versions although it is not specified in the documentation? – robertspierre Jun 07 '17 at 07:21
  • Yes, always use the constants, function declarations, and struct definitions from the Windows headers if you have them. The online docs are a starting place, but they're often wrong in some details. – Eryk Sun Jun 07 '17 at 07:25

1 Answers1

1

You need to call it like this

print("Setting the wallpaper")
SPI_SETDESKWALLPAPER = 20 
SPIF_UPDATEINIFILE = 1
ctypes.windll.user32.SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, os.path.abspath(image_file) , SPIF_UPDATEINIFILE)

Also have a look at the related documentation

robertspierre
  • 3,218
  • 2
  • 31
  • 46
  • This particular action succeeds even if the file doesn't exist or is a directory, so you may want to check `os.path.isfile(image_file)` beforehand. – Eryk Sun Jun 07 '17 at 07:43
  • It would still be better in general to use `user32 = ctypes.WinDLL('user32', use_last_error=True)`. Adding a global `windll` to ctypes was a bad idea for several reasons, the first being that shared global state is almost always a problem in waiting. – Eryk Sun Jun 07 '17 at 07:44
  • @eryksun regarding your first comment, that is really strange, because the documentation says that "When the SPI_SETDESKWALLPAPER flag is used, SystemParametersInfo returns TRUE unless there is an error (like when the specified file doesn't exist).". I did not test it, but if that is the case, if would mean that the `ctypes` library does not handle return values correctly – robertspierre Jun 07 '17 at 12:27
  • ctypes is fine here. As I said, MSDN is often wrong (e.g. bad values, wrong types and fields in structs, and inaccurate descriptions of behavior). The docs aren't written by the developers, and they're often stale or reflect what should have been implemented and no one ever actually got around to it. – Eryk Sun Jun 07 '17 at 12:40