Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Setting Wallpaper

  This sample application allows you select an image and set it as wallpaper.
3 Leaf Development

Difficulty: Easy
Time Required: 1-3 hours
Cost: Free
Software: Visual Studio Express Editions
Hardware:
Download: Download

 

Interacting visually with the Windows Desktop from code is fun, so I decided to see what it would take to change the appearance.  This sample application allows you select an image and set it as wallpaper:

It turns out that wallpaper is not directly accessible from managed code, but working with Win32 API's is no problem in this case.  Developing this application allowed me to work with methods imported from system DLL's, the registry, the file open dialog, a custom enumerated type, and use datasource binding to that enumerated type.

The application allows you to browse to an image, view a preview (resized smaller to fit if necessary), select the display style (Tiled, Stretched, or Centered), and set the image as the Desktop background.  This enabled me to work some of the new features in Visual Studio 2005 as well.  The code samples shown in this article use Visual C# 2005 Express Edition, however any of the Visual Studio Express Editions can be used to create a similar sample.  Visual Basic source code is also included with the code download for this article. Beta 2 of the Express editions can be downloaded from http://msdn.microsoft.com/express.

As seen above, the form consists of a button to browse to an image, a button to set the background to that image, a drop-down list of sizing options, and the currently selected image.  Not visible are a SplitContainer control (separating the buttons and ComboBox control from the image) and a file open dialog.  As seen in the ResearchHelp sample, the SplitContainer control is easy to use and allows the user more control over the layout of the user interface.  In the upper panel, the interactive controls have been placed, while the lower space is filled with a docked PictureBox control.

Desktop wallpaper can use one of three different sizing styles for display.  The Tiled option displays the image at full-size, repeating the image as needed, horizontally and vertically, to fill the screen.  The Stretched option displays the image at whatever size necessary to fill the screen either horizontally or vertically.  Finally, the Centered option places the image at the center of the screen, exactly once, whether if fills the screen or not, even allowing it to go beyond the edges of the screen if it is too large.  In order to support these three styles in an object-oriented way, an enumerated type was created.  This allows us to use the various style options as strongly-typed objects.  This is preferable to string or numeric representations that may not contain valid values and can cause trouble when passed to a method.

Visual C#

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

Visual Basic

Public Enum Style As Integer
    Tiled
    Centered
    Stretched
End Enum

The code that actually sets the image as wallpaper accepts the path to the image and a Style reference.  Two registry values are set in the Control Panel\Desktop key.  Based on which sizing style is requested, numeric codes are set for the WallpaperStyle and TileWallpaper values.  Using an enumerated type for the style means the value is guaranteed to match one of the three defined options -- no default case is needed.

Visual C#

RegistryKey key = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", true);
switch( style )
{
    case Style.Stretched :
        key.SetValue(@"WallpaperStyle", "2") ; 
        key.SetValue(@"TileWallpaper", "0") ;
        break;
    case Style.Centered :
        key.SetValue(@"WallpaperStyle", "1") ; 
        key.SetValue(@"TileWallpaper", "0") ; 
        break;
    case Style.Tiled :
        key.SetValue(@"WallpaperStyle", "1") ; 
        key.SetValue(@"TileWallpaper", "1") ;
        break;
}

Visual Basic

Dim key As RegistryKey = My.Computer.Registry.CurrentUser.OpenSubKey("Control Panel\Desktop", True)
Select Case selectedStyle
    Case Style.Stretched
        key.SetValue("WallpaperStyle", "2")
        key.SetValue("TileWallpaper", "0")
    Case Style.Centered
        key.SetValue("WallpaperStyle", "1")
        key.SetValue("TileWallpaper", "0")
    Case Style.Tiled
        key.SetValue("WallpaperStyle", "1")
        key.SetValue("TileWallpaper", "1")
End Select

At this point, the sizing options have been set, but the actual image path still needs to be set.  The SystemParametersInfo function exists in the user32.dll to allow you to set or retrieve hardware and configuration information from your system.  The function accepts four arguments.  The first indicates the operation to take place, the second two parameters represent data to be set, dependant on requested operation, and the final parameter allows you to specify how changes are saved and/or broadcasted.  The DllImport attribute allows you to specify a DLL, the function to call, and any required arguments.

Visual C#

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

Visual Basic

<DllImport("user32")> _
Public Shared Function SystemParametersInfo(ByVal uAction As Integer, _
     ByVal uParam As Integer, ByVal lpvParam As String, ByVal fuWinIni _   
     As Integer) As Integer
End Function

In addition to importing the function, you will need to define some constants for use with it.  The first constant represents the wallpaper operation to take place in this sample, to be used in the first argument.  The other two constants will be combined together for the final argument.

Visual C#

const int SPI_SETDESKWALLPAPER = 20;
const int SPIF_UPDATEINIFILE = 0x01;
const int SPIF_SENDWININICHANGE = 0x02;
Visual Basic
Const SPI_SETDESKWALLPAPER As Integer = 20
Const SPIF_UPDATEINIFILE As Integer = &H1&
Const SPIF_SENDWININICHANGE As Integer = &H2&

Once the function is imported, you can call it like any other.  The operation to be invoked is SPI_SETDESKWALLPAPER.  In our sample, the second argument is not needed so set to zero.  The third argument is a reference to the image path.  Note that the image must be in bitmap format.  The final argument specifies that the changes should persist, and also be immediately visible.

Visual C#

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

Visual Basic

SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, path, SPIF_UPDATEINIFILE Or SPIF_SENDWININICHANGE)

At this point, everything is in place to update the desktop wallpaper.  The user interface provides a Browse button that defaults to the Windows system directory with a *.bmp filter.  About a dozen bitmaps are available here.  The drop-down list is databound to the Style enumerated type by calling the Enum.GetNames() method in the System namespace.  This returns a string array perfect for lists and iteration.

Visual C#

styleComboBox.DataSource = System.Enum.GetNames(typeof(Wallpaper.Style));

Visual Basic

styleComboBox.DataSource = System.Enum.GetNames(GetType(Wallpaper.Style))

When the user clicks the Set button, the selected ComboBox text must be casted back to the enumerated item object.  Note that this method would throw an exception if an invalid string was passed to it, but this isn't a risk with a ComboBox.  The conversion occurs as follows:

Visual C#

(Wallpaper.Style)Enum.Parse(typeof(Wallpaper.Style), styleComboBox.Text)

Visual Basic

CType(System.Enum.Parse(GetType(Wallpaper.Style), styleComboBox.Text),            
      Wallpaper.Style)

Conclusion

The Win32 API makes it relatively easy to take advantage of features that aren't available in the .NET Framework.  A nice addition would be to use the Save() method of the Bitmap class to automatically convert images to Bitmap format so a user could select JPEG or GIF images from the local hard drive.  Download Visual C# 2005 Express Edition or Visual Basic 2005 Express Edition and give this application a try.  Get started at http://msdn.microsoft.com/express.  

Follow the Discussion

  • YingqiangYingqiang

    this porgram does not work for my computer,

    my OS is WinXP.

    It is strange, for some picture it will be ok to work correcly, but for many others, it doesn't work.

  • Clint RutkasClint I'm a "developer"

    @Yingqiang:  What are the file types that work and what won't work?  Do you see a pattern?

  • LeeLee

    Bitmaps will only work, for me at least, and probably for Yingqiang also.

    You must convert other image filetypes to a bitmap...save the bitmap...then load into systemparamentersinfo.

  • AxelAxel

    This is documented: http://msdn2.microsoft.com/en-us/library/ms724947(VS.85).aspx

    In short, BMP works on all versions and JPEG only on Vista or 2008.

  • Clint RutkasClint I'm a "developer"

    You set the program up to be a command line application and do everything through args.

  • AA

    Is there a way to make this work from CMD using RunDll32?

    Ex:  RunDll32.exe user32.dll,SystemParametersInfo 20,0,C:\path\to\wallpaper.bmp,0x01

    or something similar?

  • Clint RutkasClint I'm a "developer"

    http://windowsitpro.com/article/articleid/93152/how-can-a-batch-script-alter-the-users-screen-saver-and-wallpaper-settings-and-become-effective-without-a-logoff-and-logon.html

  • AA

    I'm actually asking more for the purpose of a batch file rather than an application.  I'm having trouble figuring out the exact syntax to use though.  Do you have any advice or resources I could check for how to properly use RunDll32 and user32.dll to change a Windows wallpaper?

  • AA

    Woohoo!  That website had so much useful information on it!  Thanks!  Though, now my problem is that Windows XP only supports using BMP files as backgrounds when setting them to

    HKEY_CURRENT_USER\Control Panel\Desktop

    which is what the "RUNDLL32.EXE user32.dll, UpdatePerUserSystemParameters" command is used to refresh.  To use a JPG image, http://windowsitpro.com/article/articleid/74578/jsi-tip-3259-windows-2000-wallpaper-policy.html suggests that I use the Active Desktop feature to load a JPG as the background.  I'm currently trying this, but I haven't yet gotten it to change within Windows without requiring a reboot (admittedly, I'm a little fuzzy on Active Desktop, so I'm still working through some options I haven't tried yet).  Do you have any words of wisdom for me on this?

    Also, out of morbid curiosity, how does Windows go about converting non-BMP images to BMP when you normally set a wallpaper anyway?

  • DZDZ

    "Also, out of morbid curiosity, how does Windows go about converting non-BMP images to BMP when you normally set a wallpaper anyway?"

    Simple. Somewhere inside your profile folder (usually C:\Documents and Settings\<your username>), there's a bitmap with the generic name "wallpaper.bmp" -- that's the actual image that's being set as the wallpaper. When Windows finds that an image isn't a wallpaper, it simply converts to BMP, rewrites the generic wallpaper file, and sets it to that, while saving the location of the original image elsewhere.

  • RossRoss

    How do I do the same for Active Desktop .jpg files?

  • MSMS

    Python on Vista:

    import ctypes

    SPI_SETDESKWALLPAPER = 0x14

    SPIF_UPDATEINIFILE = 0X01

    SPIF_SENDWININICHANGE = 0X02

    def change_paper(picture):

       try:

           ctypes.windll.user32.SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, picture, SPIF_UPDATEINIFILE|SPIF_SENDWININICHANGE)

       except:

           print("Set Wallpaper failed!")

  • tiredtired

    unfortunately this doesn't always work in vista...

  • IsaacIsaac

    I thought I'd get fancy and set my application to detect the OS version.  If it's XP, copy the jpg/gif/whatever (non-bmp) to a file with the same name .bmp in the temp folder.  Then, I'd set that to the background.  No good on XP, so there must be something more that's needed.  Has anyone been able to find a workaround for XP?  I know the OS can handle it, as you can open a JPG in a number of applications and select "Set as wallpaper" and it works.

  • IsaacIsaac

    Answered my own question.  I am converting to a BMP as so:

                   Image oldImage = Image.FromFile(sourceFile, false);

                   oldImage.Save(tempfilename, System.Drawing.Imaging.ImageFormat.Bmp);

    //sourceFile = the full path to and file name of the JPG, GIF, etc

    //tempfilename = the full path to and file name of the BMP getting created

  • DukeDuke

    wouldnt it work on vista if you just lib 64?

  • Clint RutkasClint I'm a "developer"

    @Duke, it should.  You can even make VS have a "Any CPU" setting so you don't target x86 or x64 CPUs

  • DurgeshDurgesh

    Hi!!!

    This is very good for set desktop wallpaper.

    But I want some disadvantage this project i.e.

    we can only *.bmp format file set not of

    all image formate like these *.JPG, *.GIF  etc;

    Please provide some hint(code) for others image format set wallpaper.

    Thanks & Regards

    Durgesh

    India

  • Clint RutkasClint I'm a "developer"

    @durgesh, this is a pretty old article.  The quick solution is to just save the image as a bmp?

  • JoelJoel

    Hello I am trying to use this code but I don't really understand it much. I've read through the entire article and when I pasted the code it didn't work. I'm using vbexpress 2008 and i'm not sure if i'm pasting the code properly. I'll continue messing around with it till it works but even with the select case statement its being weird. So right now i'm going to go back through the code and place some of it in separate functions just to see if that will clear anything up.

  • Clint RutkasClint I'm a "developer"

    @Joel, use the download link at the top of the page.  The articles are there to talk you through the concepts and show the harder code and the "heart of it" code.  With that being said, most articles alone won't produce a 100% functional program.

  • MeenuMeenu

    This code and document works...it really help me out.

    thanks a ton.

  • Manish Kumar BaderiyaManish Kumar Baderiya

    public enum Style: int

    {

       Tiled, Centered, Stretched

    }

    Visual Basic

    Public Enum Style As Integer

       Tiled

       Centered

       Stretched

    End Enum

    switch( style )

    {

       case Style.Stretched :

           key.SetValue(@"WallpaperStyle", "2") ;

           key.SetValue(@"TileWallpaper", "0") ;

           break;

       case Style.Centered :

           key.SetValue(@"WallpaperStyle", "1") ;

           key.SetValue(@"TileWallpaper", "0") ;

           break;

       case Style.Tiled :

           key.SetValue(@"WallpaperStyle", "1") ;

           key.SetValue(@"TileWallpaper", "1") ;

           break;

    }

  • Igor TykhyyIgor Tykhyy

    There's actually a problem.. or rather: I've got a question... if I have an animated gif, I can set it as background and it's still animated - how does it work? Does it use ActiveDesktop? can't I use it just as well? I target my "Wallpaper Changer" to XP, Vista and 7, but I don't want to use any WPF.

    And on another note: is there any way to use the wallpaper-changing-animation that comes with Windows 7 when it adjusts the paper? It slowly fades one into the other .. it'd be great if my program could do this just as well...

    I'd be glad to receive a reply Smiley,

    Igor.

  • Clint RutkasClint I'm a "developer"

    @Igor Tykhyy First part, animated gifs won't animate.  I'm confused on exactly what you're asking here on the second part.  

    You also have to remember this source code example came out before Vista was even released.

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.