Click here to Skip to main content
13,251,998 members (56,902 online)
Click here to Skip to main content
Add your own
alternative version

Stats

15.4K views
325 downloads
9 bookmarked
Posted 28 Nov 2013

Wallpaper changer prank

, 3 Dec 2013
Rate this:
Please Sign up or sign in to vote.
An app to periodically change the desktop's wallpaper.

Introduction

In our office, we have established the policy to lock your computer (Windows key + L) when you are away from it. If someone forgets to lock his/her computer, as part of the policy we have agreed, the remaining coworkers can make changes to the computer’s settings (typically changing the desktop wallpaper). When the owner of the computer comes back he knows that he forgot to lock the computer and also has a good time laughing about the prank. But, what if we could automate the process of changing someone else’s wallpaper? Furthermore, what if we could have a background process making the change whenever we want.

Background

There are quite a few articles around the web about changing a computer’s wallpaper. Describing the steps and providing sample code to achieve it. In this article I’ll be using C# and calling Win32 APIs to change the computer’s wallpaper. Next, I’ll be discussing different approaches to achieve the automation and periodical repetition of changing the computer’s wallpaper.

For the section about setting the wallpaper I’ll be using documentation from other sites (which you can find at the end of this article, in the reference section). But mainly, I’ll be using the method described by Sean Campbell in his article Setting Wallpaper (link to the article provided below).

Getting the image to display

As a first step, we need to choose the image we want to display as new wallpaper. We can either provide the path to an image we already have stored. We can provide an URL or a set of URLs to the image(s) we want to display.  However, since this is a prank, not only I want to fully control the image that will be displaying; but also when it will be displaying. To achieve this behavior I’ll be hosting a web page with the URL of the desired image. I can change the image URL whenever I want or echo an empty string to avoid a change on the wallpaper.

For instance hosted page would look as follows:

<?php
    echo "http://www.somesite.com/someimage.jpg";
?> 

Now, to retrieve the image I’ll be using C# HttpWebRequest to ping the hosted php, and retrieve the image URL in an HttpWebResponse. In addition to retrieving the image URL, I will also have the application send the host’s computer name to the PHP as POST data. That way I can store each of the soliciting computer’s names on a database and personalize the image URL for each computer/person.

The code to send the HttpRequest and get the HttpResponse would be:

/// <summary>
/// Gets the image URL with an HTTPRequest
/// </summary>
/// <param name="Uri">Site URL send the httprequest</param>
/// <param name="RequestItems">NameValueCollection with the data to send as post</param>
/// <returns>Image Url</returns>
static string getImageUrl(string Uri, NameValueCollection Items)
{
    HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(Uri);
    webrequest.KeepAlive = false;
    webrequest.Method = "POST";
    webrequest.ContentType = "application/x-www-form-urlencoded";
    string _Request = BuildRequestBody(Items);
    webrequest.ContentLength = _Request.Length;
    using (Stream writeStream = webrequest.GetRequestStream())
    {
        byte[] bytes = Encoding.ASCII.GetBytes(_Request);
        writeStream.Write(bytes, 0, bytes.Length);
        writeStream.Close();
    }

    HttpWebResponse webresponse = (HttpWebResponse)webrequest.GetResponse();            
    StreamReader responseStream = new StreamReader(webresponse.GetResponseStream(), Encoding.ASCII);
    string _Response = responseStream.ReadToEnd();
    responseStream.Close();
    webresponse.Close();

    return _Response;
} 

Downloading the Image

Once we have the image URL, we need to download it and store it on a temporal folder (you can change this folder to whatever you want). I will also change the image format and save it as a bitmap (BMP). With the method I’ll be using Windows 7 and newer versions support both BMPs and JPGs file formats for wallpapers. But to achieve compatibility with windows XP system I’m saving the image as a bit map regardless of the system the application is running. <o:p />

_imagePath = Path.Combine(Path.GetTempPath(), "wallpaper.bmp");

/// <summary>
/// Downloads an image and saves it to a temp path
/// </summary>
/// <param name="url">Uri url</param>
private static void DownloadImage(Uri url)
{
   Stream s = new System.Net.WebClient().OpenRead(url.ToString());
   Image img = Image.FromStream(s);           
   img.Save(_imagePath, System.Drawing.Imaging.ImageFormat.Bmp);
} 

Changing the Wallpaper

Changing the wallpaper is not accessible through managed code; so I’ll be calling SystemParametersInfo from the Win32 API, as proposed by Sean Campbell, which is hosted on user32.dll. This function retrieves or sets the value of one of the system-wide parameters and updates the user profile. (Detailed information on the function can be found at: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724947(v=vs.85).aspx)

The function SystemParametersInfo accepts four arguments:

  • The system-wide parameter to be retrieved or set. In this case I’m using SPI_SETDESKWALLPAPER.
  • Two parameters whose usage and format depends on the system parameter being queried or set, this parameters usually represent the data to be set with the operation that is taking place. In this case, I’m setting one as the path of the new image, and the other, since it has no use, is set up to 0.
  • The final parameter is the broadcasting options if a system parameter is being set.
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);

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

Now, for setting the style of the wallpaper, there is a registry entry under HKEY_CURRENT_USER\Control Panel\Desktop where we will add the following keys:

  • WallpaperStyle: Determines how the desktop bitmap is displayed on the desktop if the bitmap is not tiled. 
    • Value 0 to center the bitmap on the desktop.
    • Value 2 to stretch the bitmap vertically and horizontally to fit the desktop.
  • TileWallpaper:
    •  Value 1 to display the wallpaper bitmap as repeating tiles.
    •  Value 0 to display the bitmap normally 

You can find more information about this registry keys at: http://technet.microsoft.com/en-us/library/cc978626.aspx

As suggested by Sean Campbell, on his article, I will also create an Enum to hold the possible values for the wallpaper style and have a switch to properly set the values on the registry key, depending on the style selected:

case Style.Tiled:
    key.SetValue(@"WallpaperStyle", "1");
    key.SetValue(@"TileWallpaper", "1");
    break;
case Style.Centered:
    key.SetValue(@"WallpaperStyle", "1");
    key.SetValue(@"TileWallpaper", "0");
    break;
case Style.Stretched:
    key.SetValue(@"WallpaperStyle", "2");
    key.SetValue(@"TileWallpaper", "0");
    break;
case Style.Fit:
    key.SetValue(@"WallpaperStyle", "6");
    key.SetValue(@"TileWallpaper", "0");
    break;
case Style.Fill:
    key.SetValue(@"WallpaperStyle", "10");
    key.SetValue(@"TileWallpaper", "0");
    break;  

A fully detailed article Setting Wallpaper by Sean Campbell can be found at: http://channel9.msdn.com/coding4fun/articles/Setting-Wallpaper.

Adding a log on the host machine

Since the application will be running in the host machine (the unlocked computer) we won’t know if the application unexpectedly crashes, nor the reasons of the crash. So I’m adding a small .txt log file in which to store the reported exceptions, stack trace and time of the event. So if we suspect that something is not going as expected, we can later check the log file. In addition, we could also send the latest entries of the log as a web request, catch them and store them on a database. The procedure to achieve this would be the same as the procedure explained above for retrieving the image URL and sending the computer’s name. This feature is out of the scope of this article but I just wanted to write down the idea so the readers can implement it.

In order to write to the log file, I created a log Logger class which uses the StreamWriter class. The code for adding a log message is as follows:

/// <summary>
/// Adds a message entry to the log file
/// </summary>
/// <param name="message">message</param>
public void LogMessage(string message)
{
    using (sw = new StreamWriter(FilePath, true))
    {
        sw.WriteLine(string.Format("{0}\t{1}", DateTime.Now.ToString(),message));
        sw.Close();
    }
} 

Copying the application and scheduling

So far we have written an application that will send an http request with the host’s name to our php web page and retrieve an image URL. Then the image will be downloaded, stored on a temporal folder, converted to a bitmap and finally the application will set that image as the current wallpaper on the host’s machine.

So far so good. But two things are still missing:

  •  Copying the application to the host machine
  • Adding retry/loop logic in order to change the wallpaper periodically. 

To copy the file is no issue at all. You can manually do it, or we can automate it with a call to File.Copy method. But things are not that simple concerning the retry/loop logic.

For the retry/loop logic; after researching the web for the best approaches to achieve this I found the following solutions:

  • Windows service: Implement a windows service with the same code as the application.
  •  Have the application running on the background looping and waiting: Modify the actual application to keep it always running on the background.
  • Windows task scheduler: Use windows task scheduler to trigger the launch of our application. 

Let’s discuss each of the following options. First we have windows services. This is probably the most efficient and reliable approach. Unfortunately for our purposes, changing the desktop wallpaper cannot be done through a windows service. Changing the desktop wallpaper depends on the user that is currently logged. It is a user specific task; whereas services run in their own session. Services run on an isolated and independent session from any of the users’ sessions, for security reasons. So, since we want to modify a user’s session wallpaper, doing this through windows services is unfeasible.

Since changing the wallpaper is a user specific task our only option so far is to have an application run the code within the user’s session. As second approach we could modify our coded application adding a thread logic that will loop forever, changing the wallpaper and sleeping for some minutes. A second approach following the same loop/retry logic would be the use of C# Timer ElapsedEventHandler. The result would be the creation of a timer that will repeat each X minutes and call the change wallpaper function each time the event is launched:

Timer imageChangeTimer = new Timer(5000);
imageChangeTimer.Elapsed += new ElapsedEventHandler(imageChangeTimer_Elapsed);
imageChangeTimer.Start(); 

Both approaches work, but they would need to have the application alive and running on the background forever. According to some forums, this approach is far from desirable. Having an application always running on the background to execute only an action every period of time will only consume the computer’s resources even when our application is on idle periods.

Finally, the best approach for our needs, and ironically the simplest and easiest to implement is to use Windows Task Scheduler. We can easily have our application run every X minutes by scheduling a task with Windows Task Scheduler. I’ll be using Schtasks.exe (Task Scheduler command line) to schedule a run of the application each 5 minutes. The full documentation and options of Schtasks.exe can be found here: http://msdn.microsoft.com/en-us/library/windows/desktop/bb736357%28v=vs.85%29.aspx

To summarize what we have just discussed, we have just seen that to periodically change the desktop wallpaper the best approach is to use Windows Task Scheduler. So, I’ll be creating a second application that will achieve the last two missing points we have discussed. This second application will copy our first application to a “save folder” on the host machine and schedule a Windows task for our recently copied executable.

Using C# Diagnostics.Process class we can easily automate the scheduling of the task as follows:

Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = @"schtasks";
p.StartInfo.Arguments = string.Format("/create /tn {0} /tr {1} /sc MINUTE /mo 5", 
        "\"AppVshost32\"", path);
p.Start();
p.WaitForExit();

Final touches

I have written the application as a console application. As a final touch, in order to hide the application and raise no suspicion on the user that a new application has been launched I’ll hide the console window by changing the “Output type” of my Visual Studio project to “Windows Application”. You can change this property under Project -> Properties -> Application in Visual Studio.

Finally, after a long trail we have come up with two applications.  Our main application that changes the user’s wallpaper and a second application, let us call it our installer, which automates the process of copying the main application to a secure folder and sets up Windows Task Scheduler to periodically launch the application on the background.

Conclusions

This article showed the integration of multiple technologies and approaches to achieve a programming prank. Nonetheless, the methods and approaches discussed here regarding the repetition and automation of the application have more potential to offer, maybe under a different context (not a prank).  I hope that more than the code exposed on this article, the ideas, options and alternatives exposed here prove to be useful to the reader and enlightens the perspective about automation and its full potential on daily activities.

References and important links:

Besides the mentioned links in the body of the article. I would like to mention the following articles which where useful to me while researching the topic:

Articles to set the wallpaper using C#:

License

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

Share

About the Author

deoxys
United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

 
QuestionAll that's missing.... Pin
2374118-Sep-15 10:33
member2374118-Sep-15 10:33 
GeneralMy vote of 4 Pin
webmaster44223-Apr-15 3:13
memberwebmaster44223-Apr-15 3:13 
GeneralMy vote of 1 Pin
pt14013-Dec-13 11:37
memberpt14013-Dec-13 11:37 
SuggestionRe: My vote of 1 Pin
John B Oliver11-Dec-13 11:43
memberJohn B Oliver11-Dec-13 11:43 
GeneralRe: My vote of 1 Pin
Marco Bertschi12-Dec-13 2:31
professionalMarco Bertschi12-Dec-13 2:31 
GeneralRe: My vote of 1 Pin
pt140112-Dec-13 3:32
memberpt140112-Dec-13 3:32 

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.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.171114.1 | Last Updated 3 Dec 2013
Article Copyright 2013 by deoxys
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid