How to restore windows desktop wallpaper to Slideshow and Windows Spotlight mode in C#?

Antoine Gorin 40 Reputation points
2024-07-30T12:13:56.76+00:00

Context

I have a console application in .Net 6 C# that changes the current user's desktop wallpaper to an image for a given time. I backup the current wallpaper configuration of the user by reading the registry. At the end of the givent time, I would like to restore the wallpaper configuration the user had at the beginning.

I managed to restore the image mode and color mode but I didn't managed to restore Slideshow nor Windows Spotlight mode. Ideally I'd like it to work on Windows 10, 11, Windows Server 2016, 2019 and 2022 (I realize there might be differences between thos environments).

The keys I use to read the curent configuration

HKCU\Control Panel\Desktop\Wallpaper      # to read the wallpaper image filepath
HKCU\Control Panel\Desktop\WAllpaperStyle # to read the wallpaper image style (fill, fit ...)
HKCU\Control Panel\Colors\Background      # to read the background color
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Wallpapers\BackgroundType # to read the background mode (image, color, slideshow, windows spotlight)

Solutions for restoring Image and colors

To restore the image I used the IDesktopWallpaper interface and to restore colors, I used registry keys:

HKCU\Control Panel\Colors\Background # to restore the saved color
HKCU\Control Panel\Desktop\Wallpaper = "" # to not show any image
HKCU\Control Panel\Desktop\WallpaperStyle = 0
HKCU\Control Panel\Desktop\TileWallpaper = 0

I then called the following function to refresh the desktop by reading the registry.

SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, null, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);

Solutions tried for restoring Slideshow

I tried 2 solutions: using the IDesktopWallpaper interface with SetSlideshow() and setting some registry keys.

For the IDesktopWallpaper.SetSlideshow, I don't know how I can transform from a List<File> to a IShellItemArray. (see https://learn.microsoft.com/fr-fr/windows/win32/api/shobjidl_core/nf-shobjidl_core-idesktopwallpaper-setslideshow)

For the registry solution, I tried setting the following registry keys but the wallpaper simply switch from image mode to color mode.

HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Wallpapers\SlideshowEnabled = 1 # Activate slideshow mode
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Wallpapers\SlideshowDirectoryPath = "My/Specific/Folder/Path" # Specifies the folder to scan for images
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Wallpapers\SlideshowTickCount = 60000 # Specifies the delay between two images
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Wallpapers\BackgroundType = 2 # Specifies the slideshow mode

HKCU\Control Panel\Personalization\Desktop Slideshow\Interval = 60000 # For any reasons there is an other key to specify the delay between two images
HKCU\Control Panel\Personalization\Desktop Slideshow\Shuffle = 0 # Whether or not images should be displayed in random order

HKCU\Control Panel\Desktop\Wallpaper = "" # to not show any image
HKCU\Control Panel\Desktop\WallpaperStyle = 6 # apparently this could have a role in specifying slideshow mode
HKCU\Control Panel\Desktop\TileWallpaper = 0

Are there any other API that exists that I didn't mention? Am I missing something in the slideshow configuration?

Bonus Question: Is it possible to restore the Windows spotlight mode for wallpaper?

Windows for business | Windows Client for IT Pros | User experience | Other
Developer technologies | C#
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 90,686 Reputation points
    2024-07-30T13:25:52.6966667+00:00

    For the IDesktopWallpaper.SetSlideshow, I don't know how I can transform from a List<File> to a IShellItemArray.

    This test works for me on Windows 10 :

                IShellItem pShellItem = null;
                IShellItemArray pShellItemArray = null;
                HRESULT hr = SHCreateItemFromParsingName(@"E:\Tools\Graphism\Images", IntPtr.Zero, typeof(IShellItem).GUID, out pShellItem);
                if (hr == HRESULT.S_OK)
                {
                    hr = SHCreateShellItemArrayFromShellItem(pShellItem, typeof(IShellItemArray).GUID, out pShellItemArray);
                    if (hr == HRESULT.S_OK)
                    {
                        IDesktopWallpaper pDesktopWallpaper = (IDesktopWallpaper)(new DesktopWallpaperClass());
                        hr = pDesktopWallpaper.SetSlideshow(pShellItemArray);
                    }
                }  
    

    with : (I don't post IDesktopWallpaper as you said you use it)

            [ComImport()]
            [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            [Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
            public interface IShellItem
            {
                [PreserveSig()]
                HRESULT BindToHandler(IntPtr pbc, ref Guid bhid, ref Guid riid, ref IntPtr ppv);
                HRESULT GetParent(ref IShellItem ppsi);
                HRESULT GetDisplayName(SIGDN sigdnName, ref System.Text.StringBuilder ppszName);
                HRESULT GetAttributes(uint sfgaoMask, ref uint psfgaoAttribs);
                HRESULT Compare(IShellItem psi, uint hint, ref int piOrder);
            }
            
            public enum SIGDN : int
            {
                SIGDN_NORMALDISPLAY = 0x0,
                SIGDN_PARENTRELATIVEPARSING = unchecked((int)0x80018001),
                SIGDN_DESKTOPABSOLUTEPARSING = unchecked((int)0x80028000),
                SIGDN_PARENTRELATIVEEDITING = unchecked((int)0x80031001),
                SIGDN_DESKTOPABSOLUTEEDITING = unchecked((int)0x8004C000),
                SIGDN_FILESYSPATH = unchecked((int)0x80058000),
                SIGDN_URL = unchecked((int)0x80068000),
                SIGDN_PARENTRELATIVEFORADDRESSBAR = unchecked((int)0x8007C001),
                SIGDN_PARENTRELATIVE = unchecked((int)0x80080001)
            }
            
            [ComImport()]
            [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            [Guid("b63ea76d-1f85-456f-a19c-48159efa858b")]
            public interface IShellItemArray
            {
                HRESULT BindToHandler(IntPtr pbc, ref Guid bhid, ref Guid riid, ref IntPtr ppvOut);
                HRESULT GetPropertyStore(GETPROPERTYSTOREFLAGS flags, ref Guid riid, ref IntPtr ppv);
                HRESULT GetPropertyDescriptionList(REFPROPERTYKEY keyType, ref Guid riid, ref IntPtr ppv);
                HRESULT GetAttributes(SIATTRIBFLAGS AttribFlags, int sfgaoMask, ref int psfgaoAttribs);
                HRESULT GetCount(ref int pdwNumItems);
                HRESULT GetItemAt(int dwIndex, ref IShellItem ppsi);
                HRESULT EnumItems(ref IntPtr ppenumShellItems);
            }
            
            public enum SIATTRIBFLAGS
            {
                SIATTRIBFLAGS_AND = 0x1,
                SIATTRIBFLAGS_OR = 0x2,
                SIATTRIBFLAGS_APPCOMPAT = 0x3,
                SIATTRIBFLAGS_MASK = 0x3,
                SIATTRIBFLAGS_ALLITEMS = 0x4000
            }
            
            public enum HRESULT : int
            {
                S_OK = 0,
                S_FALSE = 1,
                E_NOINTERFACE = unchecked((int)0x80004002),
                E_NOTIMPL = unchecked((int)0x80004001),
                E_FAIL = unchecked((int)0x80004005)
            }
            
            public enum GETPROPERTYSTOREFLAGS
            {
                GPS_DEFAULT = 0,
                GPS_HANDLERPROPERTIESONLY = 0x1,
                GPS_READWRITE = 0x2,
                GPS_TEMPORARY = 0x4,
                GPS_FASTPROPERTIESONLY = 0x8,
                GPS_OPENSLOWITEM = 0x10,
                GPS_DELAYCREATION = 0x20,
                GPS_BESTEFFORT = 0x40,
                GPS_NO_OPLOCK = 0x80,
                GPS_PREFERQUERYPROPERTIES = 0x100,
                GPS_EXTRINSICPROPERTIES = 0x200,
                GPS_EXTRINSICPROPERTIESONLY = 0x400,
                GPS_MASK_VALID = 0x7FF
            }
    
            [StructLayout(LayoutKind.Sequential, Pack = 4)]
            public struct REFPROPERTYKEY
            {
                private Guid fmtid;
                private int pid;
                public Guid FormatId
                {
                    get
                    {
                        return this.fmtid;
                    }
                }
                public int PropertyId
                {
                    get
                    {
                        return this.pid;
                    }
                }
                public REFPROPERTYKEY(Guid formatId, int propertyId)
                {
                    this.fmtid = formatId;
                    this.pid = propertyId;
                }
                public static readonly REFPROPERTYKEY PKEY_DateCreated = new REFPROPERTYKEY(new Guid("B725F130-47EF-101A-A5F1-02608C9EEBAC"), 15);
            }
            
           	[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
           	public static extern HRESULT SHCreateItemFromParsingName(string pszPath, IntPtr pbc, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv);
    
           	[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
           	public static extern HRESULT SHCreateShellItemArrayFromShellItem(IShellItem psi, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItemArray ppv);
    
    
    
    2 people found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.