Click here to Skip to main content
15,118,508 members
Articles / Programming Languages / C#
Article
Posted 23 Oct 2012

Tagged as

Stats

22.4K views
1.1K downloads
16 bookmarked

Daily Wallpaper Changer

Rate me:
Please Sign up or sign in to vote.
4.81/5 (7 votes)
22 Apr 2013CPOL2 min read
Yet another wallpaper changer

Introduction

This application downloads an image from the internet and puts it as the desktop wallpaper.

There are several sites that show a daily image. One of those is bing.com. It offers great pictures every day as the background in their site. Our application will download images from Bing and two other image providers.

Background

There are a lot of articles about setting up the desktop background, but I'll give this article an internet approach and get cool images from the cloud.

About the code 

Basic flow:

Image 1

The application has eight classes that are distributed in the following way:

DailyImage.cs

This is an abstract class that contains some common methods and defines an abstract method called ImageUrl(). This method must be overridden by all its "child classes". 

C#
using System;
using System.IO;
using System.Net;
using System.Globalization;
 
namespace Wallpaper.Providers
{
    abstract class DailyImage
    {
        /// <summary>
        /// Downloads an image from internet
        /// </summary>
        /// <param name="url">Url where the image can be found</param>
        /// <returns>path to the local file</returns>
        public string DownloadImg(string url) {
            string path = Directory.GetCurrentDirectory() + "\\" + 
              DateTime.Now.ToString("yyyyMMddHHmmssffff", 
              CultureInfo.InvariantCulture) + ".jpg";
            using(WebClient webClient = new WebClient()){
                webClient.DownloadFile(url, path);
            }
            return path;
        }
 
        /// <summary>
        /// Perform a get http request and resturn it's content
        /// </summary>
        /// <param name="url">request url</param>
        /// <returns>response content</returns>
        public string Request(string url)
        {
            string response = "";
            using (WebClient webClient = new WebClient())
            {
                response = webClient.DownloadString(url);
            }
            return response;
        }
 
        /// <summary>
        /// Returns the url of a daily image from a specific provider
        /// </summary>
        /// <returns>url ready to be downloader</returns>
        public abstract string ImageUrl();
    }
}

Bing.cs => Gets the daily image from Microsoft's search service.

C#
using System.Text.RegularExpressions;
namespace Wallpaper.Providers
{
    /// <summary>
    /// Retrieve the last available wallpaper from bing.com
    /// </summary>
    class Bing : DailyImage
    {
        const string BING_URL = "http://www.bing.com";
        /// <summary>
        /// Returns the url of a daily image from a specific provider
        /// </summary>
        /// <returns>url of the image to download</returns>
        public override string ImageUrl(){
            string response = base.Request(BING_URL);
            string pattern = @"g_img={url:'([a-zA-Z0-9\/\?=%_.]+)";
            MatchCollection matches = Regex.Matches(response, pattern);
 
            return (matches.Count > 0) ? matches[0].Groups[1].Value : string.Empty;
        }
    }
}

Nasa.cs => Gets the daily image from the site: http://apod.nasa.gov/apod/.

C#
using System.Text.RegularExpressions;

namespace Wallpaper.Providers
{
    /// <summary>
    /// Retrieve the last available image from Astronomy Picture of the Day
    /// </summary>
    class Nasa : DailyImage
    {
        const string ASTRONOMY_PICTURE_OF_THE_DAY = "http://apod.nasa.gov/apod/";
        /// <summary>
        /// Returns the url of a daily image from a specific provider
        /// </summary>
        /// <returns>url of the image to download</returns>
        public override string ImageUrl(){
            string response = base.Request(ASTRONOMY_PICTURE_OF_THE_DAY);
            string pattern = @"<IMG SRC=.([a-zA-Z0-9\/\?=%_.]+)";
            MatchCollection matches = Regex.Matches(response, pattern);

            return (matches.Count > 0) ? matches[0].Groups[1].Value : string.Empty;
        }
    }
}

Wallppr.cs => Gets a random image from the site: http://www.dailywallppr.com.

C#
using System.Text.RegularExpressions;
 
namespace Wallpaper.Providers
{
    /// <summary>
    /// Retrieve a random wallpaper from dailywallppr.com
    /// </summary>
    class Wallppr : DailyImage
    {
        const string WALLPPR_URL = "http://www.dailywallppr.com/index.php?p=pics&id=random";
        /// <summary>
        /// Returns the url of a daily image from a specific provider
        /// </summary>
        /// <returns>url of the image to download</returns>
        public override string ImageUrl(){
            string response = base.Request(WALLPPR_URL);
            string pattern = @"(http://www.dailywallppr.com/prev.*.jpg)";
            MatchCollection matches = Regex.Matches(response, pattern);
            
            return (matches.Count > 0) ? matches[0].Groups[1].Value : string.Empty;
        }
    }
}

NotFound.cs => This class will be instantiated if ProviderFactory is not able to find a valid image provider.

C#
using System;
 
namespace Wallpaper.Providers
{
    class NotFound : DailyImage
    {
        const string ERROR = "Provider was not found, please check the app.config file";
        public override string ImageUrl()
        {
            Console.WriteLine(ERROR);
            Environment.Exit(0);
            return string.Empty;
        }
    }
}

Class Diagram:

Image 2

ProviderFactory.cs 

This class has only one static method called GetInstance that will return an object according to the specified provider name. I implemented this with reflection instead of using a switch or if/else statements for maintainability purposes.

C#
using System;
using System.Linq;
using System.Reflection;
 
namespace Wallpaper.Providers
{
    class ProviderFactory
    {
        private ProviderFactory()
        {
        }
 
        public static DailyImage GetInstance(string name)
        {
            var found = Assembly.GetExecutingAssembly().GetTypes().SingleOrDefault(t => t.Name == name);
            //if found return the instance of the found type, if not a NotFound
            return (found == null) ? new NotFound() : (DailyImage)Activator.CreateInstance(found);
        }
    }
}

Wallpaper.cs

The class that will be in charge of setting up the desktop background image.  

Here's the code:

C#
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Globalization;
 
namespace Wallpaper
{
    class Wallpaper
    {
        private Wallpaper(){
        
        }
 
        const int SPI_SETDESKWALLPAPER = 20;
        const int SPIF_UPDATEINIFILE = 0x01;
        const int SPIF_SENDWININICHANGE = 0x02;
        
        public enum Style{Centered, Tiled, Stretched}
 
        /// <summary>
        /// Change the current wallpaper
        /// </summary>
        /// <param name="path" />Path to the image
        /// <param name="style" />one value from the Style enum
        /// <param name="deleteImg" />delete the image after the operation?
        public static void Set(string path, Style style, bool deleteImg)
        {
            RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true);
            string styleCode = ((int)style).ToString(CultureInfo.InvariantCulture);
            key.SetValue("WallpaperStyle", styleCode);
            key.SetValue("TileWallpaper", styleCode);
 
            NativeMethods.SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, 
                   path,SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
            //delete image file
            if (deleteImg)
                System.IO.File.Delete(path);
 
        }
    }
 
    internal static class NativeMethods
    {
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        internal static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
    }
}

Program.cs

This is the file that we all know because by default this file contains the main method, and in our case this file will make the required calls to change the current wallpaper to a new one.

C#
using System;
using Wallpaper.Providers;
using System.Configuration;
 
namespace Wallpaper
{
    class Program
    {
        static void Main()
        {
            //All the pictures on this website are gathered on the internet, and belong to their respective owners.
            string provider = ConfigurationManager.AppSettings["provider"];
            string deleteImg = ConfigurationManager.AppSettings["delete_img"];
            DailyImage oDailyImage = ProviderFactory.GetInstance(provider);
 
            //Retrieve the url of the image
            string imageUrl = oDailyImage.ImageUrl();
            //Download and catch the local file name
            string localPath = oDailyImage.DownloadImg(imageUrl);
            bool deleteFile = (string.IsNullOrEmpty(deleteImg)||(deleteImg.Equals("1")));
            //set the desired wallpaper and delete the file if desired
            Wallpaper.Set(localPath, Wallpaper.Style.Stretched, deleteFile);
        }
    }
}

Configuration file:

Inside the configuration file of our application you will find:

XML
<?xml version="1.0"?>
<configuration>
  <appSettings>
    <!--Available provider are: Bing, Nasa and Wallppr-->
    <add key="provider" value="Wallppr"/>
    <add key="delete_img" value="1"/>
  </appSettings>
<startup><supportedRuntime version="v4.0" 
  sku=".NETFramework,Version=v4.0"/></startup></configuration>
<configuration>
</configuration>

Points of Interest  

Factory method with reflection:

This technique allows us to keep maintainability in our project and it will help us keep the Open/Closed principle.

Regex: 

Very useful when we need to extract data inside other data, in this case the image URLs.

NullObject pattern: 

I created a NotFound class in order to prevent the application from fails when the factory method is unable to find a valid object. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Carlos Luis Rojas Aragonés
Chief Technology Officer https://golabstech.com
Costa Rica Costa Rica
CTO and Co-founder of Golabs, a software development company located in Costa Rica. I am very passionate about my job and I really enjoy building things with software and make things happening. I am also a professor at Universidad Técnica Nacional because I believe that knowledge should be shared, I really enjoy seeing people grow from students at the university to great professionals and entrepreneurs.

Comments and Discussions

 
QuestionUpdate ? Pin
Patrice Dargenton18-Mar-17 3:13
MemberPatrice Dargenton18-Mar-17 3:13 
AnswerRe: Update ? Pin
Carlos Luis Rojas Aragonés20-Mar-17 7:10
professionalCarlos Luis Rojas Aragonés20-Mar-17 7:10 
I wrote this a while ago, I have no plans to update this soon, however I can help you if you need anything special or want to create something based on this.

Kind regards

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.