2009-06-30 9 views

risposta

87

Ecco una classe strappato da un app che ho scritto un anno o due anni fa:

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); 
    } 
} 

non ho ancora testato estensivamente, in modo da utilizzare a proprio rischio.

+0

In questo modo verranno impostati solo i file BMP. Se voglio impostare un JPEG qual è il metodo? – Sauron

+1

Non sono sicuro se windows supporta jpeg come sfondo ... converte altre immagini in bmp prima di configurarlo come sfondo (correggimi se sbaglio) se questo è il caso devi fare la conversione nel tuo codice –

+5

Sto usando questo per jpegs va bene. Solo perché è chiamato bmp nel codice sopra non lo limita. probabilmente * lavorerà per png e gif e anche altri, ma non l'ho verificato. –

-2

risposta di Tweaking Neal N per Gif:

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(); 
} 

Si noti inoltre che è necessario utilizzare:

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; 

Infine, fare clic destro sul vostro progetto, Aggiungi riferimento, e (negli assiemi e Framework) aggiungi Presentation Core, System.Xaml e WindowsBase.

Quindi fare clic con il pulsante destro del mouse sul progetto e accedere a Proprietà e verificare che il framework di destinazione sia .Net Framework 4.5. Se si modifica questo potrebbe essere necessario riavviare Visual Studio.

+2

Ovviamente impantanarsi la macchina. C'è un ciclo infinito di blocco con una chiamata a 'Thread.Sleep' gettata a casaccio. Ci sono modi molto migliori per aspettare che il tempo passi. –

+0

No, penso che abbia più a che fare con la chiamata a SystemParametersInfo (per esempio, 10 volte al secondo). Il desktop non è pensato per essere aggiornato in questo modo. Questo è evidenziato da "explorer" che va da 0% a 6-12% di utilizzo della CPU, semplicemente eseguendo un programma che chiama questo metodo. Ho ottimizzato la mia risposta, aggiungendo metodi asincroni e facendo la chiamata al thread. Dormi meno spammy (succede solo quando necessario). Qualche altra preoccupazione lampante? – Phylliida

+0

Ho preso in considerazione la modifica per fermare i thread con un altro metodo, ma sembra che esagerare con un metodo che probabilmente non è tale buona pratica in primo luogo. – Phylliida

7

basi sulla this useful answer, ho anche fatto my own app di impostare la risoluzione dello schermo corrispondente carta da parati.

Ma le impostazioni del Registro di sistema erano errate. Ecco i valori corretti (testati su 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()); 
} 
+0

Perché usare (numero) .ToString()? Perché no "(numero)"? – HighTechProgramming15

+0

Certo che puoi. È una questione di concetto - l'ho scritto così perché qualcun altro l'ha fatto. – badsamaritan

Problemi correlati