Изменение обоев рабочего стола с помощью кода в .NET

Как изменить обои рабочего стола с помощью кода С#?


person Sauron    schedule 30.06.2009    source источник


Ответы (5)


Вот класс, взятый из приложения, которое я написал год или два назад:

public sealed class Wallpaper
{
    Wallpaper() { }

    const int SPI_SETDESKWALLPAPER = 20;
    const int SPIF_UPDATEINIFILE = 0x01;
    const int SPIF_SENDWININICHANGE = 0x02;

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);

    public enum Style : int
    {
        Tiled,
        Centered,
        Stretched
    }

    public static void Set(Uri uri, Style style)
    {
        System.IO.Stream s = new System.Net.WebClient().OpenRead(uri.ToString());

        System.Drawing.Image img = System.Drawing.Image.FromStream(s);
        string tempPath = Path.Combine(Path.GetTempPath(), "wallpaper.bmp");
        img.Save(tempPath, System.Drawing.Imaging.ImageFormat.Bmp);

        RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true);
        if (style == Style.Stretched)
        {
            key.SetValue(@"WallpaperStyle", 2.ToString());
            key.SetValue(@"TileWallpaper", 0.ToString());
        }

        if (style == Style.Centered)
        {
            key.SetValue(@"WallpaperStyle", 1.ToString());
            key.SetValue(@"TileWallpaper", 0.ToString());
        }

        if (style == Style.Tiled)
        {
            key.SetValue(@"WallpaperStyle", 1.ToString());
            key.SetValue(@"TileWallpaper", 1.ToString());
        }

        SystemParametersInfo(SPI_SETDESKWALLPAPER,
            0,
            tempPath,
            SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
    }
}

Я не проверял это широко, так что используйте на свой страх и риск.

person Neil N    schedule 30.06.2009
comment
Это установит только файлы BMP. Если я хочу установить JPEG, каков метод? - person Sauron; 30.06.2009
comment
Не уверен, что Windows поддерживает jpeg в качестве обоев... он преобразует другие изображения в bmp перед установкой в ​​качестве обоев (поправьте меня, если я ошибаюсь), если это так, вам нужно выполнить преобразование в своем коде. - person Umair Ahmed; 30.06.2009
comment
Я использовал это для jpeg просто отлично. Просто потому, что в приведенном выше коде он называется bmp, это не ограничивает его. это вероятно будет работать для png и gif, а также для других файлов, но я этого не проверял. - person Neil N; 30.06.2009
comment
приведенный выше код берет jpg (при передаче в функцию set) и сохраняет его как временный bmp, а затем устанавливает его. При повторной установке ... он просто перезаписывает этот временный bmp новым. - person Neil N; 30.06.2009
comment
@NeilN Это здорово, но как насчет того, чтобы добавить флажок Пустые обои, чтобы сделать обои черными! - person Murhaf Sousli; 11.04.2012
comment
К вашему сведению: этот код не работает с PNG. Сначала мне пришлось конвертировать в BMP вручную. - person Program.X; 08.08.2013
comment
@UmairAhmed, наполовину правда, наполовину ложь, Windows поддерживает все основные форматы изображений, то есть для этого и нужны типы файлов. однако он в основном использует bmp (32-битный собственный bmp / ​​bmpx с поддержкой альфа-слоя) для большинства изображений пользовательского интерфейса ... но, например, экран входа в систему представляет собой стандартное изображение jpg с именем backgrounddefault.jpg с ограничением размера 256 КБ, даже если системные соединения остаются jpg, а windows не использует bmp(x) в процессе. (Windows 7 и более поздние версии) IE, если вам по какой-то причине нужен альфа-слой, ознакомьтесь с документацией по 32-битному BMP и т. Д. - person LokizFenrir; 23.10.2014
comment
Вы можете сделать это, используя команду пакетного файла и выполнив пакетную команду, используя Process См. этот вопрос SO: stackoverflow.com/questions/7779491/ - person Quintonn; 05.03.2015
comment
Вау! Это полностью работает и поддерживает JPG... Действительно хорошая работа. Поздравляю. - person Umut D.; 18.04.2015

Основываясь на этом полезном ответе, я также сделал мое собственное приложение, чтобы установить обои, соответствующие разрешению экрана.

Но настройки реестра были неправильными. Вот правильные значения (проверено на Win 7, Win 8.1, Win 10).

if (style == Style.Fill)
{
    key.SetValue(@"WallpaperStyle", 10.ToString());
    key.SetValue(@"TileWallpaper", 0.ToString());
}
if (style == Style.Fit)
{
    key.SetValue(@"WallpaperStyle", 6.ToString());
    key.SetValue(@"TileWallpaper", 0.ToString());
}
if (style == Style.Span) // Windows 8 or newer only!
{
    key.SetValue(@"WallpaperStyle", 22.ToString());
    key.SetValue(@"TileWallpaper", 0.ToString());
}
if (style == Style.Stretch)
{
    key.SetValue(@"WallpaperStyle", 2.ToString());
    key.SetValue(@"TileWallpaper", 0.ToString());
}
if (style == Style.Tile)
{
    key.SetValue(@"WallpaperStyle", 0.ToString());
    key.SetValue(@"TileWallpaper", 1.ToString());
}
if (style == Style.Center)
{
    key.SetValue(@"WallpaperStyle", 0.ToString());
    key.SetValue(@"TileWallpaper", 0.ToString());
}
person badsamaritan    schedule 03.12.2016
comment
Зачем использовать (число).ToString()? Почему нет (число)? - person HighTechProgramming15; 28.02.2017
comment
Конечно, можно. Это вопрос концепции — я написал это так, потому что это сделал кто-то другой. - person badsamaritan; 20.03.2017

Если вы используете UWP в c#, ​​вот код, который я нашел здесь

using Windows.System.UserProfile; 

// Pass in a relative path to a file inside the local appdata folder 
async Task<bool> SetWallpaperAsync(string localAppDataFileName) 
{ 
   bool success = false; 
   if (UserProfilePersonalizationSettings.IsSupported())       
   {
       var uri = new Uri("ms-appx:///Local/" + localAppDataFileName);
       StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(uri);
       UserProfilePersonalizationSettings profileSettings = UserProfilePersonalizationSettings.Current;
       success = await profileSettings.TrySetWallpaperImageAsync(file);
   }
}

На самом деле я думаю, что это может быть проще file.png это ваша фотография, это может быть .jpg или что-то еще

StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync("file.png", CreationCollisionOption.ReplaceExisting);
bool success = false;
UserProfilePersonalizationSettings profileSettings = UserProfilePersonalizationSettings.Current;
success = await profileSettings.TrySetWallpaperImageAsync(file);
person Poyi Hong    schedule 28.10.2019

Если вы хотите временно установить обои для рабочего стола, не загрязняя историю настроек Windows, вот что я сделал.

Он создает резервную копию истории обоев (хранящейся в реестре) перед установкой временные обои, и вы можете восстановить их обратно впоследствии.

https://gist.github.com/Drarig29/4aa001074826f7da69b5bb73a83ccd39

person Drarig29    schedule 17.08.2020

Настройка ответа Нила Н для Gifs:

private const int SPI_SETDESKWALLPAPER = 20;
private const int SPIF_UPDATEINIFILE = 0x01;
private const int SPIF_SENDWININICHANGE = 0x02;

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);

public enum Style : int
{
    Tiled,
    Centered,
    Stretched
}

/// <summary>
/// Loops numFrames times, animating the desktop background as the given gif.
/// Remember this will sorta bog down your computer, and probably isn't best to be running 24/7.
/// If numFrames is negative this will loop forever
/// </summary>
/// <param name="gifPath">The gif to be animated</param>
/// <param name="transparencyReplace">If the gif has transparency, it will be "replaced" with this color.</param>
/// <param name="framesPerSecond">How many frames to play per second. This is a max: most likely it will be a little slower than this especially at first.</param>
/// <param name="style">Whether to tile, center, or stretch each gif frame as it's played.</param>
/// <param name="numFrames">The number of frames to play. If negative, this method will loop forever.</param>
public static void SetDesktopBackgroundAsGifAsync(string gifPath, System.Drawing.Color transparencyReplace, int framesPerSecond, Style style, int numFrames)
{
    Thread workerThread = new Thread(() => SetDesktopBackgroundAsGif(gifPath, transparencyReplace, framesPerSecond, style, numFrames));
    workerThread.Start();
}

/// <summary>
/// Loops numFrames times, animating the desktop background as the given gif.
/// Remember this will sorta bog down your computer, and probably isn't best to be running 24/7.
/// If num frames is negative this will loop forever. 
//// <summary>
/// <param name="gifPath">The gif to be animated</param>
/// <param name="backgroundImage">Image to render the gif on top of (because of transparency)</param>
/// <param name="framesPerSecond">How many frames to play per second. This is a max: most likely it will be a little slower than this.</param>
/// <param name="style">Whether to tile, center, or stretch each gif frame as it's played.</param>
/// <param name="numFrames">The number of frames to play. If negative, this method will loop forever.</param>
public static void SetDesktopBackgroundAsGifAsync(string gifPath, System.Drawing.Image backgroundImage, int framesPerSecond, Style style, int numFrames)
{
    Thread workerThread = new Thread(() => SetDesktopBackgroundAsGif(gifPath, backgroundImage, framesPerSecond, style, numFrames));
    workerThread.Start();
}

/// <summary>
/// Loops numFrames times, animating the desktop background as the given gif.
/// Remember this will sorta bog down your computer, and probably isn't best to be running 24/7. 
/// if numFrames is negative this will loop forever
/// </summary>
/// <param name="gifPath">The gif to be animated</param>
/// <param name="transparencyReplace">If the gif has transparency, it will be "replaced" with this color.</param>
/// <param name="framesPerSecond">How many frames to play per second. This is a max: most likely it will be a little slower than this.</param>
/// <param name="style">Whether to tile, center, or stretch each gif frame as it's played.</param>
/// <param name="numFrames">The number of frames to play. If negative, this method will loop forever.</param>
public static void SetDesktopBackgroundAsGif(string gifPath, System.Drawing.Color transparencyReplace, int framesPerSecond, Style style, int numFrames)
{
    if (!File.Exists(gifPath))
        throw new Exception("Given gif: '" + gifPath + "' not found");

    FileStream gifFile = new FileStream(gifPath, FileMode.Open);

    GifBitmapDecoder gifDecoder = new GifBitmapDecoder(gifFile, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);

    if (gifDecoder.Frames.Count == 0)
        throw new Exception("No frames in given gif");

    Bitmap backgroundImage = new Bitmap(gifDecoder.Frames[0].PixelWidth, gifDecoder.Frames[0].PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

    using(Graphics g = Graphics.FromImage(backgroundImage))
    {
        g.FillRectangle(new System.Drawing.SolidBrush(transparencyReplace), 0, 0, gifDecoder.Frames[0].PixelWidth, gifDecoder.Frames[0].PixelHeight);
    }

    gifFile.Close();

    SetDesktopBackgroundAsGif(gifPath, backgroundImage, framesPerSecond, style, numFrames);
}

/// <summary>
/// Loops infinitely, animating the desktop background as the given gif.
/// Remember this will sorta bog down your computer, and probably isn't best to be running 24/7. 
/// </summary>
/// <param name="gifPath">The gif to be animated</param>
/// <param name="backgroundImage">Image to render the gif on top of (because of transparency)</param>
/// <param name="framesPerSecond">How many frames to play per second. This is a max: most likely it will be a little slower than this.</param>
/// <param name="style">Whether to tile, center, or stretch each gif frame as it's played.</param>
/// <param name="numFrames">The number of frames to play. If negative, this method will loop forever.</param>
private static void SetDesktopBackgroundAsGif(string gifPath, System.Drawing.Image backgroundImage, int framesPerSecond, Style style, int numFrames)
{
    if (!File.Exists(gifPath))
        throw new Exception("Given gif: '" + gifPath + "' not found");

    FileStream gifFile = new FileStream(gifPath, FileMode.Open);

    GifBitmapDecoder gifDecoder = new GifBitmapDecoder(gifFile, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);

    if (gifDecoder.Frames.Count == 0)
        throw new Exception("No frames in given gif");

    Console.WriteLine("Saving frames to temporary files:");

    int numFramesSoFar = 0;

    for (int i = 0; i < gifDecoder.Frames.Count; i++)
    {
        BitmapFrame gifFrame = gifDecoder.Frames[i];
        PngBitmapEncoder pngEncoder = new PngBitmapEncoder();
        pngEncoder.Frames.Add(gifFrame);
        MemoryStream pngStream = new MemoryStream();
        pngEncoder.Save(pngStream);
        Image frameImage = Image.FromStream(pngStream);
        Bitmap bmp = new Bitmap(frameImage.Width, frameImage.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.DrawImage(backgroundImage, 0, 0);
            g.DrawImageUnscaled(frameImage, 0, 0);
        }
        string tempPath = Path.Combine(Path.GetTempPath(), gifPath + i + ".bmp");
        bmp.Save(tempPath, System.Drawing.Imaging.ImageFormat.Bmp);

        Console.WriteLine("Saved frame " + i);

        numFramesSoFar++;

        if (numFrames >= 0 && numFramesSoFar >= numFrames) break;
    }

    Console.WriteLine("Setting frames to desktop background at about " + framesPerSecond + " FPS");

    // 1.0/... to convert to seconds per frame (instead of frames per second)
    // * 1000 to convert to milliseconds per frame
    // * 1000 to convert to microseconds per frame
    // * 10 to convert to 0.1s of microseconds per frame = 100s of nanoseconds per frame
    long ticksBetweenFrames = (long)Math.Round(1.0 / framesPerSecond) * 1000*1000*10;

    Stopwatch timer = new Stopwatch();
    timer.Start();

    numFramesSoFar = 0;

    while(numFrames < 0 || numFramesSoFar < numFrames)
    {
        for (int i = 0; i < gifDecoder.Frames.Count; i++)
        {
            // Sleep until we're at the desired frame rate, if needed.
            if(ticksBetweenFrames > timer.ElapsedTicks)
                Thread.Sleep(new TimeSpan(Math.Max(0, ticksBetweenFrames - timer.ElapsedTicks)));

            timer.Restart();

            // From http://stackoverflow.com/a/1061682/2924421

            string filePath = Path.Combine(Path.GetTempPath(), "wallpaper" + i + ".bmp");

            RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true);

            if (style == Style.Stretched)
            {
                key.SetValue(@"WallpaperStyle", 2.ToString());
                key.SetValue(@"TileWallpaper", 0.ToString());
            }

            if (style == Style.Centered)
            {
                key.SetValue(@"WallpaperStyle", 1.ToString());
                key.SetValue(@"TileWallpaper", 0.ToString());
            }

            if (style == Style.Tiled)
            {
                key.SetValue(@"WallpaperStyle", 1.ToString());
                key.SetValue(@"TileWallpaper", 1.ToString());
            }

            SystemParametersInfo(SPI_SETDESKWALLPAPER,
                0,
                filePath,
                SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);

            numFramesSoFar++;

            if (numFrames >= 0 && numFramesSoFar >= numFrames) break;
        }
    }

    gifFile.Close();
}

Также обратите внимание, что вам нужно использовать:

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;

Наконец, щелкните правой кнопкой мыши свой проект, добавьте ссылку и (в сборках и инфраструктуре) добавьте Presentation Core, System.Xaml и WindowsBase.

Затем щелкните правой кнопкой мыши свой проект и перейдите в «Свойства» и убедитесь, что Target Framework — это .Net Framework 4.5. Если вы измените это, вам может потребоваться перезапустить Visual Studio.

person Phylliida    schedule 18.05.2014
comment
Конечно, это гложет машину. Есть блокирующий бесконечный цикл со случайным вызовом Thread.Sleep. Есть гораздо лучшие способы подождать, пока истечет время. - person Cody Gray; 18.05.2014
comment
Нет, я думаю, это больше связано с вызовом SystemParametersInfo (скажем, 10 раз в секунду). Рабочий стол не предназначен для такого обновления. Об этом свидетельствует переход проводника с 0% до 6-12% использования процессора, просто запустив программу, которая вызывает этот метод. Однако я изменил свой ответ, добавив асинхронные методы и сделав вызов Thread.Sleep менее спамным (происходит только при необходимости). Любые другие вопиющие опасения? - person Phylliida; 18.05.2014
comment
Я подумал о том, чтобы настроить его, чтобы остановить потоки другим методом, но похоже, что он выходит за рамки метода, который, вероятно, не является хорошей практикой в ​​первую очередь. - person Phylliida; 18.05.2014
comment
С другой стороны, я добавил параметр numFrames, который указывает количество кадров, которые вы хотите анимировать, прежде чем этот метод остановится. Если отрицательный, то навсегда. - person Phylliida; 18.05.2014
comment
Ждать и слушать что? - person Phylliida; 24.10.2014