如何使用IDesktopWallpaper实现桌面壁纸幻灯片效果
实现Windows桌面壁纸幻灯片效果
我已经通过DesktopWallpaper类实现了单张桌面壁纸的设置,代码如下:
public static void SetDesktopWallpaper(string imagePath, DesktopWallpaperPosition wallpaperPosition) { IDesktopWallpaper wallpaper = DesktopWallpaper.WallpaperWrapper.GetWallpaper(); wallpaper.SetPosition(wallpaperPosition); wallpaper.SetWallpaper(null, imagePath); Marshal.ReleaseComObject(wallpaper); }
但现在需要实现多张图片的幻灯片轮换效果,不清楚SetSlideshow(IntPtr items)的参数如何传入图片路径列表,现有类定义如下:
public class DesktopWallpaper { [StructLayout(LayoutKind.Sequential)] public struct Rect { public int Left; public int Top; public int Right; public int Bottom; } public enum DesktopSlideshowOptions { ShuffleImages = 0x01 } public enum DesktopSlideshowState { Enabled = 0x01, Slideshow = 0x02, DisabledByRemoteSession = 0x04 } public enum DesktopSlideshowDirection { Forward = 0, Backward = 1 } public enum DesktopWallpaperPosition { Center = 0, Tile = 1, Stretch = 2, Fit = 3, Fill = 4, Span = 5 } [ComImport, Guid("B92B56A9-8B55-4E14-9A89-0199BBB6F93B"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IDesktopWallpaper { void SetWallpaper([MarshalAs(UnmanagedType.LPWStr)] string monitorID, [MarshalAs(UnmanagedType.LPWStr)] string wallpaper); [return: MarshalAs(UnmanagedType.LPWStr)] string GetWallpaper([MarshalAs(UnmanagedType.LPWStr)] string monitorID); [return: MarshalAs(UnmanagedType.LPWStr)] string GetMonitorDevicePathAt(uint monitorIndex); [return: MarshalAs(UnmanagedType.U4)] uint GetMonitorDevicePathCount(); [return: MarshalAs(UnmanagedType.Struct)] Rect GetMonitorRECT([MarshalAs(UnmanagedType.LPWStr)] string monitorID); void SetBackgroundColor([MarshalAs(UnmanagedType.U4)] uint color); [return: MarshalAs(UnmanagedType.U4)] uint GetBackgroundColor(); void SetPosition([MarshalAs(UnmanagedType.I4)] DesktopWallpaperPosition position); [return: MarshalAs(UnmanagedType.I4)] DesktopWallpaperPosition GetPosition(); void SetSlideshow(IntPtr items); IntPtr GetSlideshow(); void SetSlideshowOptions(DesktopSlideshowDirection options, uint slideshowTick); [PreserveSig] uint GetSlideshowOptions(out DesktopSlideshowDirection options, out uint slideshowTick); void AdvanceSlideshow([MarshalAs(UnmanagedType.LPWStr)] string monitorID, [MarshalAs(UnmanagedType.I4)] DesktopSlideshowDirection direction); DesktopSlideshowDirection GetStatus(); bool Enable(); } public static class WallpaperWrapper { static readonly Guid CLSID_DesktopWallpaper = new Guid("{C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD}"); public static IDesktopWallpaper GetWallpaper() { Type typeDesktopWallpaper = Type.GetTypeFromCLSID(CLSID_DesktopWallpaper); return (IDesktopWallpaper)Activator.CreateInstance(typeDesktopWallpaper); } } }
解决方法
SetSlideshow(IntPtr items)的参数实际是指向IShellItemArray接口的指针,需要将图片路径列表转换为这个COM对象后传入。以下是完整实现:
1. 添加必要的COM接口定义
需要补充IShellItem和IShellItemArray的COM导入定义,以及用于创建ShellItem的系统API:
[ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IShellItem { void BindToHandler(IntPtr pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid bhid, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IntPtr ppv); void GetParent(out IShellItem ppsi); void GetDisplayName(SIGDN sigdnName, out IntPtr ppszName); void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs); void Compare(IShellItem psi, uint hint, out int piOrder); } [ComImport, Guid("B63EA76D-1F85-456F-A19C-48159EFA858B"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IShellItemArray { void BindToHandler(IntPtr pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid bhid, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IntPtr ppv); void GetPropertyStore(int flags, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IntPtr ppv); void GetPropertyDescriptionList(IntPtr keyType, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IntPtr ppv); void GetAttributes(uint dwAttribFlags, uint sfgaoMask, out uint psfgaoAttribs); uint GetCount(); void GetItemAt(uint index, out IShellItem ppsi); void EnumItems(out IEnumShellItems ppenumShellItems); } [ComImport, Guid("7F73BE3F-FB79-493C-A6C7-7EE14E245841"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IEnumShellItems { uint Next(uint celt, [Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface, SizeParamIndex = 0)] IShellItem[] rgelt, out uint pceltFetched); void Skip(uint celt); void Reset(); void Clone(out IEnumShellItems ppenum); } public enum SIGDN : uint { SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, } public static class Shell32 { [DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)] public static extern void SHCreateItemFromParsingName( [MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppsi); [DllImport("shell32.dll", PreserveSig = false)] public static extern void SHCreateShellItemArrayFromShellItems( uint cItems, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface)] IShellItem[] apsitems, out IShellItemArray ppia); }
2. 实现设置幻灯片的方法
添加静态方法,将图片路径列表转换为IShellItemArray并传入SetSlideshow:
public static void SetDesktopSlideshow(List<string> imagePaths, uint slideIntervalSeconds, DesktopWallpaperPosition position, bool shuffle) { if (imagePaths == null || imagePaths.Count == 0) throw new ArgumentException("图片路径列表不能为空"); IDesktopWallpaper wallpaper = DesktopWallpaper.WallpaperWrapper.GetWallpaper(); try { // 转换路径为IShellItem数组 List<IShellItem> shellItems = new List<IShellItem>(); Guid shellItemGuid = typeof(IShellItem).GUID; foreach (string path in imagePaths) { if (!File.Exists(path)) throw new FileNotFoundException("图片不存在", path); Shell32.SHCreateItemFromParsingName(path, IntPtr.Zero, shellItemGuid, out IShellItem item); shellItems.Add(item); } // 创建IShellItemArray Shell32.SHCreateShellItemArrayFromShellItems((uint)shellItems.Count, shellItems.ToArray(), out IShellItemArray itemArray); // 设置幻灯片 IntPtr itemArrayPtr = Marshal.GetComInterfaceForObject(itemArray, typeof(IShellItemArray)); wallpaper.SetSlideshow(itemArrayPtr); // 设置切换间隔(单位:毫秒) DesktopSlideshowDirection options = shuffle ? (DesktopSlideshowDirection)((int)DesktopSlideshowDirection.Forward | (int)DesktopSlideshowOptions.ShuffleImages) : DesktopSlideshowDirection.Forward; wallpaper.SetSlideshowOptions(options, slideIntervalSeconds * 1000); // 设置壁纸位置 wallpaper.SetPosition(position); // 启用幻灯片 wallpaper.Enable(); // 释放资源 Marshal.Release(itemArrayPtr); Marshal.ReleaseComObject(itemArray); foreach (var item in shellItems) Marshal.ReleaseComObject(item); } finally { Marshal.ReleaseComObject(wallpaper); } }
3. 调用示例
// 示例:设置3张图片,每10秒切换一次,填充模式,随机播放 List<string> imagePaths = new List<string> { @"C:\Wallpapers\img1.jpg", @"C:\Wallpapers\img2.jpg", @"C:\Wallpapers\img3.jpg" }; SetDesktopSlideshow(imagePaths, 10, DesktopWallpaperPosition.Fill, true);
关键说明
SetSlideshow接收的IntPtr是IShellItemArray接口的指针,必须通过Shell32的API创建该对象- 切换间隔单位是毫秒,需将秒数乘以1000转换
DesktopSlideshowOptions.ShuffleImages是标记位,需和DesktopSlideshowDirection组合使用- 所有COM对象使用后必须手动释放,避免内存泄漏
内容的提问来源于stack exchange,提问作者Chibako
相关产品推荐
相关产品推荐

