Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

Customisation with VB - Changing Logon Backgrounds in Windows 7

4.85/5 (14 votes)
24 Jan 2010CPOL9 min read 54.3K   2.4K  
Using VB to change Windows 7 logon backgrounds
LogonBackgroundChanger_bin

Introduction

Remember the old days? A time when your choice when it came to logon screen backgrounds was essentially clouds, clouds, or more clouds? Well now, with Windows 7, those days are over! This is the first Windows OS to come with an in-built capacity to feature a custom logon screen background natively, without any third-party tools or hacks, and the key to all this (including a handy little tool to change your logon screen) will be covered in this article on using the Registry to manipulate Windows 7 login screens in VB.NET.

Background

In this article, I will be guiding you through the creation of a very handy little piece of software called "Logon Background Changer" (okay, so I'm not very good at naming things, shall we continue?) that is capable of changing the login screen background using the Registry and a little bit of GDI+ to help us along and to add a little extra to the application.

Windows Versions

Any version of Windows 7 will work just fine for this article, but any other Windows Operating System just doesn't support this functionality. With other versions of Windows, you may have to rely on complicated or manual hacks to get the logon screen background that you want.

The Rules

Firstly, any image that is to become a logon screen on Windows 7 has to meet certain criteria. I'll bet you're thinking "I knew there was a catch!", but the criteria are reasonable (if a little strange):

  1. The image must be less than 256 kilobytes (262144 bytes) in size. If it exceeds this, Windows just simply doesn't display it, using the default screen instead.
  2. The image has to be in JPEG format (with a *.jpg extension).
  3. The image has to be in a specific directory on-disk, and must have a specific name (more on this later).

Other than these simple rules, it is effectively possible to change the background to anything that you want.

So Where Are the Images Stored?

The background image files are usually stored in a specific directory on-disk: C:\Windows\System32\oobe\Info\Backgrounds.

In this instance, "C" is your hard disk that contains your Windows 7 installation. Each file is stored with a name according to the resolution at which it is applied:

  • backgroundDefault.jpg
  • background768x1280.jpg
  • background900x1440.jpg
  • background960x1280.jpg
  • background1024x1280.jpg
  • background1280x1024.jpg
  • background1024x768.jpg
  • background1280x960.jpg
  • background1600x1200.jpg
  • background1440x900.jpg
  • background1920x1200.jpg
  • background1280x768.jpg
  • background1360x768.jpg

For instance, if your monitor is set at a resolution of 1280x1024, the background with the name "background1280x1024.jpg" will be used as your logon background, and if it's at 1360x768, the image file with the name containing that resolution will be applied to your logon screen. If a file that matches your resolution cannot be found, then "backgroundDefault.jpg" is scaled to fit your monitor's current resolution and then applied.

Don't Forget the Registry!

So that's it, right? I'm afraid not! There's a very important step that is easy to forget when it comes to customising a login screen, and that's making the necessary Registry tweak. In this case, the Registry key: HKLM\Software\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\Background, needs to have the value "OEMBackground" changed from 0 to 1. If the value is 0, Windows simply ignores the custom images in the folder on-disk, instead applying the in-built logon background. However, if the key contains a value of 1, Windows will attempt to apply one of your custom backgrounds.

Now that we know how Windows 7 handles and displays logon backgrounds, it's time to get started on creating our simple, sweet, and very useful piece of software.

Using the Code

We will only be changing and manipulating three things on the user's computer with our software:

  1. The image located at C:\Windows\System32\oobe\info\backgrounds\backgroundDefault.jpg; we could expand the software to handle all different resolutions. But for the purpose of this article, we'll only be changing the stretch-to-fit background.
  2. The Registry value OEMBackground located at HKLM\Software\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\Background for obvious reasons.
  3. A small Registry value of our own to neatly hold the file path of our current logon background, called PersistFile, that is located in the key: HKEY_LOCAL_MACHINE\SOFTWARE\LogonBackgroundChanger.

Sounds simple, doesn't it? It is, though we'll be adding a few useful little pieces of code of our own along the way to enhance the experience for our users.

The UI

Here's a map of what our finished user interface will look like, with short descriptions of what each control is designed to do (more details later on in the article):

LabelledUI.png

There is really only one important control on this entire form, and that is the "Apply" button. When that is clicked, all the action takes place in the event handler: tasks such as tweaking the Registry and converting the selected file to a .jpg file all happen when this button is pressed.

Step 1: Check the OS!

Before we do anything to the Registry or do anything with the file system, it would be wise to check the computer's OS version because our program will be simply useless on any version of Windows prior to Windows 7. This is as simple as putting this on the beginning of the event handler for the click event of the "Apply" button:

VB.NET
'Check OS Version [
If Not My.Computer.Info.OSFullName.StartsWith("Microsoft Windows 7") Then
    MessageBox.Show("You must be running Microsoft Windows 7 in order " & _ 
                    "to use this program", "Error", _
                    MessageBoxButtons.OK, MessageBoxIcon.Error, _
                    MessageBoxDefaultButton.Button1)
    Exit Sub
End If
']

This will stop anybody trying to use this utility on the wrong OS because, while it will not do any harm, it will certainly be of absolutely no use unless it is used on Windows 7.

Step 2: Get the Windows Installation Directory...

Now, this step is slightly more complicated. We have to take into account the variability between where users have their Windows 7 OS installed. Heck, it might not even be on the C drive or, for that matter, in a folder name "Windows" at all. That's where the Windows API comes in:

VB.NET
Private Declare Function GetWindowsDirectory Lib "kernel32" Alias _
  "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long

This function takes a couple of slightly scary arguments used to properly retrieve the Windows installation folder, but what it lacks in programmer-friendliness, it makes up by eliminating that small risk that our users will have a different Windows directory than the usual.

However, to make things easier, it helps to wrap up this API call with a neat little function that will handle the setup of the buffer for us, like so:

VB.NET
''' <summary>
''' Returns the path of the windows installation directory.
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Private Function GetPath() As String

'Create Buffer [
GetPath = Space(255)
']

'Return Windows Directory Path [
Call GetWindowsDirectory(GetPath, Len(GetPath))
']

End Function

So in the "Apply" event handler, we will place this code after the OS check:

VB.NET
'Get Windows Directory [
 Dim WindowsInstallPath As String
 WindowsInstallPath = GetPath().Trim().TrimEnd(Chr(0)) & "\"
']

Now, the function of this is to remove all the null characters from the end of the string that GetPath() returns. This is because if we tried to use these in the next piece of code, we'd get an error saying "Invalid Characters".

Step 3: Create Missing Folders

It's really important for solid code that we don't assume anything in our programming, that's why we use the following piece of code next, to ensure that our users have the correct folders for setting up a logon background:

VB.NET
'Create Missing Folders [
If Not My.Computer.FileSystem.DirectoryExists(WindowsInstallPath & _
                   "System32\oobe\info") Then
  My.Computer.FileSystem.CreateDirectory(WindowsInstallPath & _
                         "System32\oobe\info")
End If
If Not My.Computer.FileSystem.DirectoryExists(WindowsInstallPath & _
                   "System32\oobe\info\backgrounds") Then
  My.Computer.FileSystem.CreateDirectory(WindowsInstallPath & _
                         "System32\oobe\info\backgrounds")
End If
']

If our users don't have the correct folders, we create them, thus ensuring we don't try to save an image to a nonexistent folder later.

Step 4: Check File Paths

Next, in the event handler, we'll be checking that the picture file specified for the background actually exists on-disk, and also if the user entered anything at all! We do this like so:

VB.NET
'Check For Blank Box [
If FileSelectionBox.Text.Trim = "" Then

'Ask To Select [
Dim MyResult As DialogResult = MessageBox.Show("There is no picture file" & _ 
             " selected, would you like to select one now?", _
             "No File Selected", MessageBoxButtons.YesNo, _
             MessageBoxIcon.Warning)
']

'Confirmation [
Select Case MyResult
Case Windows.Forms.DialogResult.Yes

'Offer Selection [
ButtonBrowse_Click(Me, e)
']

End Select
']

'Exit Method [
Exit Sub
']

End If
']

'Check File Exists [
If Not My.Computer.FileSystem.FileExists(FileSelectionBox.Text) Then

'Show Error And Abort [
MessageBox.Show("The image file specified does not exist, please ensure " & _ 
                "that it is present on your computer.", _
                "Error - File Not Found", MessageBoxButtons.OK, _
                MessageBoxIcon.Error)
Exit Sub
']

End If
']

If the user hasn't entered anything, we offer to open the dialog to select a file by calling the event handler for the "Browse..." button if the user answers "Yes" to the dialog that we present. If their file path doesn't exist, we ask them to correct it.

Step 5: Check File Size

Now, this sounds really simple, right? We just use some standard code to get the size of the file and see if it's small enough. However, in this case, it's not quite that simple. We'll use the Bitmap object to change any PNG or BMP files that we're given into a JPEG, if necessary. That means that the file will shrink (in most cases) by quite a large amount. We'll need to save the reformatted JPEG to a temporary file to check if it's small enough to use, with the following code:

VB.NET
Try

'Create Temporary File [
Dim TemporaryName As String = FileIO.FileSystem.GetTempFileName
']

'Reformat [
Dim ChangeToJPEG As New Bitmap(FileSelectionBox.Text)
']

'Save Reformatted File [
ChangeToJPEG.Save(TemporaryName, System.Drawing.Imaging.ImageFormat.Jpeg)
']

'Release Bitmap [
ChangeToJPEG.Dispose()
']

'Get Temporary File Size [
Dim MyInformation As New IO.FileInfo(TemporaryName)
If MyInformation.Length > 262144 Then

'Delete Temporary File [
If MyInformation.Exists() Then
MyInformation.Delete()
End If
']

'Error [
MessageBox.Show("The image file specified would be over 256KB " & _ 
    "when converted to a JPG file and too large to use. " & _ 
    "Please select another file.", "Error - File Too Large", _
    MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
']

End If
']

'Delete Temporary File [
If MyInformation.Exists() Then
MyInformation.Delete()
End If
']

Catch MyException As Exception

'Format Error [
MessageBox.Show("The image file specified is not of the correct format. " & _
   "Logon Background Changer cannot convert it to JPG format " & _ 
   "for use as a logon screen. Please select another file.", _
   "Error - Incorrect Format", MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
']

End Try

This will simply take the file and attempt to reformat and save it as a JPEG temporarily, just to check its size. If it can't be converted to a JPEG or the converted JPEG would be too large, a message box is shown and the operation is aborted.

Step 6: Enable or Disable Background

This section of code is next, simply changing the custom background from inactive to active or vice-versa, depending on the state of the checkbox on our form:

VB.NET
'Enable Or Disable Background [
Dim MyEnableSelection As Integer
If UseScreenCheck.Checked Then
  MyEnableSelection = 1
Else
  MyEnableSelection = 0
End If

My.Computer.Registry.SetValue("HKEY_LOCAL_MACHINE\SOFTWARE\" & _ 
  "Microsoft\Windows\CurrentVersion\Authentication\LogonUI\Background", _
  "OEMBackground", MyEnableSelection)
']
Step 7: Changing the Background

Now finally, after all these checks and conversions, we are ready to change the file "backgroundDefault.jpg" on-disk to reflect our changes, with the following code:

VB.NET
'Finally Change Screen [
Try

'Reformat [
Dim MyFinalPath As String = WindowsInstallPath & _
    "System32\oobe\info\backgrounds\backgroundDefault.jpg"
Dim ChangeToJPEG As New Bitmap(FileSelectionBox.Text)
']

'Delete Old File [
If My.Computer.FileSystem.FileExists(MyFinalPath) Then
My.Computer.FileSystem.DeleteFile(MyFinalPath)
End If
']

'Save Reformatted File [
ChangeToJPEG.Save(MyFinalPath, System.Drawing.Imaging.ImageFormat.Jpeg)
']

'Release Bitmap [
ChangeToJPEG.Dispose()
']

'Set Registry File Containing Path [            
My.Computer.Registry.SetValue(_
  "HKEY_LOCAL_MACHINE\SOFTWARE\LogonBackgroundChanger", _
  "PersistFile", FileSelectionBox.Text)
']

Catch MyException As Exception

MessageBox.Show("The image file specified is not of the correct format. " & _ 
   "Logon Background Changer cannot convert it to JPG format for use " & _ "
   as a logon screen. Please select another file.", _
   "Error - Incorrect Format", MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub

End Try
']

'Show Success [
MessageBox.Show("The changes were successfully applied.", _
  "Changes Saved", MessageBoxButtons.OK, MessageBoxIcon.Information)
']

This code just reformats the image file as a JPEG, and saves it in the correct place for Windows to identify it as a logon background. It also changes a little Registry key for use exclusively by our program, which holds the path of our selected file before we copied it to the logon background folder. This is just a little convenience for our users, and is accessed again and used in the Load event handler for our main form:

VB.NET
Private Sub Form_Main_Load(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles MyBase.Load

'Get Registry Values [
FileSelectionBox.Text = My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE" & _ 
    "\LogonBackgroundChanger", "PersistFile", "")
Dim MyEnableSelection As Integer = _
    My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE" & _ 
    "\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\Background", _
    "OEMBackground", 0)
If MyEnableSelection > 0 Then
UseScreenCheck.Checked = True
Else
UseScreenCheck.Checked = False
End If
']

End Sub

This code just retrieves any values from the Registry (namely the OEMBackground value that dictates whether to use the custom background or not, and our own little value that holds the file path of the background file most recently selected) and updates our UI to reflect them.

Wrapping Up

That's our software's most important functions in-depth, and hopefully, the comments in the code itself will offer more of an insight into its inner workings. I won't bore you with the details of the 'Help' form or, indeed, the 'Exit' button, but feel free to dissect them as you see fit. This application could be extended to a great degree to incorporate previews of logon screens and customisable logon screens for different resolutions. For now, however, I leave you with a starting point and an example of how to manipulate the Registry and file system using VB to achieve the logon screen that you want!

Credits

  • A huge thank you to Mark James for his silk icon pack (used in the application). Visit his site here.

History

  • 20/01/2010 - Article uploaded
  • 22/01/2010 - Article updated
  • 23/01/2010 - Article updated

License

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