Last week’s post, Improving the GrabAPicture Application (Part 3), began the process of modifying the forms to accept the special wallpaper settings supported by Windows 7 and newer versions of the Windows operating system. That post also stressed the need to make the forms flexible enough to support older versions of the operating system. The forms actually detect which operating system is in use and modify their appearance to match the capability of the operating system. This week you’ll see the code used to make the new settings work properly. Of course, these two posts together support the second objective outlined in the Improving the GrabAPicture Application (Part 1) post.
Modifying WinWallpaper.vb
The underlying code is less critical when it comes to detecting the operating system because the form already performs this task. The user can’t select an option that doesn’t work with the selected operating system if the forms don’t make that option available. Consequently, a lot of the changes in this example are straightforward. The first change is to extend the Styles enumeration initially discussed in the Exploring the GrabAPicture Application (Part 5) post as shown in the following code.
' A list of wallpaper display styles.
Public
Enum
Styles
As
Integer
Tiled
Centered
Stretched
Unknown
Fit
Fill
End
Enum
Notice that I add the new options after Unknown to ensure that they don’t inadvertently affect any of the application code. Some developers might be tempted to add the options before Unknown, but this would be a mistake because you can’t be absolutely certain about potential side effects of doing so.
Now that you have the right enumerations available, it’s time to modify the code that relies on the enumerations. Before you can do anything though, you need to determine what values to provide for the two new enumerations. Remember that in the Exploring the GrabAPicture Application (Part 7) post that the HKEY_CURRENT_USER\Control Panel\Desktop registry key WallpaperStyle value contains the information you need. When you set the desktop to use the Fit style, this value becomes 6 as shown here.

Setting the desktop wallpaper to Fill changes this value to 10. Consequently, the first change you need to make is to the Style() property (discussed in the Exploring the GrabAPicture Application (Part 7) post) as shown here.
Public
Property
Style()
As
Styles
Get
' Contains the registry key that holds the
' desktop values.
Dim
StyleKey
As
RegistryKey
' Get the desktop key.
StyleKey = _
Registry.CurrentUser.OpenSubKey( _
"Control Panel\Desktop"
,
False
)
' Obtain the current value.
If
StyleKey.GetValue(
"WallpaperStyle"
) = 2
And
_
StyleKey.GetValue(
"TileWallpaper"
) = 0
Then
Return
Styles.Stretched
End
If
If
StyleKey.GetValue(
"WallpaperStyle"
) = 1
And
_
StyleKey.GetValue(
"TileWallpaper"
) = 0
Then
Return
Styles.Centered
End
If
If
StyleKey.GetValue(
"WallpaperStyle"
) = 1
And
_
StyleKey.GetValue(
"TileWallpaper"
) = 1
Then
Return
Styles.Tiled
End
If
' Windows 7 and above-specific values.
If
StyleKey.GetValue(
"WallpaperStyle"
) = 6
And
_
StyleKey.GetValue(
"TileWallpaper"
) = 0
Then
Return
Styles.Fit
End
If
If
StyleKey.GetValue(
"WallpaperStyle"
) = 10
And
_
StyleKey.GetValue(
"TileWallpaper"
) = 0
Then
Return
Styles.Fill
End
If
' This value should only show up if someone has
' tampered with the registry and set the values
' incorrectly.
Return
Styles.Unknown
End
Get
Set
(
ByVal
Value
As
Styles)
' Because Styles.Unknown signifies an error
' condition, the developer can't provide it as an
' input value.
If
Value = Styles.Unknown
Then
Throw
New
ArgumentException( _
"Cannot use Styles.Unknown as an input argument"
)
End
If
' Contains the registry key that holds the
' desktop values.
Dim
StyleKey
As
RegistryKey
' Get the desktop key.
StyleKey = _
Registry.CurrentUser.OpenSubKey( _
"Control Panel\Desktop"
,
True
)
' Select one of the other input values and set the
' registry keys as needed.
Select
Case
Value
Case
Styles.Stretched
StyleKey.SetValue(
"WallpaperStyle"
,
"2"
)
StyleKey.SetValue(
"TileWallpaper"
,
"0"
)
Case
Styles.Centered
StyleKey.SetValue(
"WallpaperStyle"
,
"1"
)
StyleKey.SetValue(
"TileWallpaper"
,
"0"
)
Case
Styles.Tiled
StyleKey.SetValue(
"WallpaperStyle"
,
"1"
)
StyleKey.SetValue(
"TileWallpaper"
,
"1"
)
' Provide Windows 7 and above-specific values.
Case
Styles.Fit
StyleKey.SetValue(
"WallpaperStyle"
,
"6"
)
StyleKey.SetValue(
"TileWallpaper"
,
"0"
)
Case
Styles.Fill
StyleKey.SetValue(
"WallpaperStyle"
,
"10"
)
StyleKey.SetValue(
"TileWallpaper"
,
"0"
)
End
Select
End
Set
End
Property
All of the required changes are marked with comments so you can find them easily. In all cases, it’s simply a matter of making the right registry changes. The behavior of the code remains unchanged.
During testing, I found that if the value of the WallpaperStyle registry setting is set to either 6 or 10 on a Windows XP system, Windows assumes you mean stretched (the option normally associated with a value of 2). Testing on a Vista system shows the same thing happens. I’ll be interested to hear from readers whether this is the case on their systems. If not, the example may very well need to include additional operating system-specific code for the Style() property.
Modifying the Command Line Interface
There is one place where things can get incredibly messy, and that’s with the command line interface. The Exploring the GrabAPicture Application (Part 9) post describes the command line interface in detail. In addition, you’ve already seen on update to this interface in the Improving the GrabAPicture Application (Part 2) post. In order to add the new Windows 7 functionality to the command line, you’ll need to perform another update of it that includes operating system version checking similar to the checking provided for the forms. For now, we’ll leave the command line interface alone and save this update for another time.
However, in order to keep the command line interface from working improperly, you do need to implement a few changes to the /Random command line switch code. This code ensures that the Windows 7 and above-specific settings are handled when working with random wallpaper selections as shown here:
If
CmdArg.ToUpper() =
"/RANDOM"
Then
' Current application settings.
Dim
CurrentSettings
As
GrabAPictureSettings
' Number of settings to randomize.
Dim
Settings
As
Int32 = 0
' The selected image number.
Dim
Selection
As
Int32 = 0
' Contains the wallpaper location.
Dim
NewUri
As
Uri
' Wallpaper manipulation class.
Dim
Wallpaper
As
New
WinWallpaper
' Initialize the stored settings.
CurrentSettings = GrabAPictureSettings.LoadSettings()
' Verify that there are settings to use.
If
CurrentSettings
Is
Nothing
Then
MessageBox.Show( _
"This application isn't configured to use random sources."
)
Return
-1
End
If
' Obtain the number of settings to randomize.
If
CurrentSettings.LocalChecked
And
CurrentSettings.RemoteChecked
Then
' Detect configuration errors.
If
CurrentSettings.LocalUris
Is
Nothing
Or
_
CurrentSettings.RemoteUris
Is
Nothing
Then
MessageBox.Show(
"Application not set up to use "
+ _
"both local and remote locations."
)
Return
-2
End
If
' Determine the number of settings.
Settings = CurrentSettings.LocalUris.Length + _
CurrentSettings.RemoteUris.Length - 1
' Randomize the settings.
Randomize(DateTime.Now.Millisecond)
Selection = Convert.ToInt32(Settings * Rnd())
' Obtain the style and location.
If
Selection < CurrentSettings.LocalUris.Length
Then
' Choose the wallpaper style.
Select
Case
CurrentSettings.LocalUris(Selection).Style
Case
WinWallpaper.Styles.Stretched
Wallpaper.Style = WinWallpaper.Styles.Stretched
Case
WinWallpaper.Styles.Centered
Wallpaper.Style = WinWallpaper.Styles.Centered
Case
WinWallpaper.Styles.Tiled
Wallpaper.Style = WinWallpaper.Styles.Tiled
' Add the Windows 7 and above-specific options.
Case
WinWallpaper.Styles.Fit
Wallpaper.Style = WinWallpaper.Styles.Fit
Case
WinWallpaper.Styles.Fill
Wallpaper.Style = WinWallpaper.Styles.Fill
End
Select
' Create a wallpaper URI.
NewUri =
New
Uri(CurrentSettings.LocalUris(Selection).Location)
Else
' Subtract the local resources.
Selection -= CurrentSettings.LocalUris.Length
' Choose the wallpaper style.
Select
Case
CurrentSettings.RemoteUris(Selection).Style
Case
WinWallpaper.Styles.Stretched
Wallpaper.Style = WinWallpaper.Styles.Stretched
Case
WinWallpaper.Styles.Centered
Wallpaper.Style = WinWallpaper.Styles.Centered
Case
WinWallpaper.Styles.Tiled
Wallpaper.Style = WinWallpaper.Styles.Tiled
' Add the Windows 7 and above-specific options.
Case
WinWallpaper.Styles.Fit
Wallpaper.Style = WinWallpaper.Styles.Fit
Case
WinWallpaper.Styles.Fill
Wallpaper.Style = WinWallpaper.Styles.Fill
End
Select
' Create a wallpaper URI.
NewUri =
New
Uri(CurrentSettings.RemoteUris(Selection).Location)
End
If
' Set the wallpaper location.
Wallpaper.WallpaperURI = NewUri
ElseIf
CurrentSettings.LocalChecked
Then
' Detect configuration errors.
If
CurrentSettings.LocalUris
Is
Nothing
Then
MessageBox.Show(
"Application not set up "
+ _
"to use local locations."
)
Return
-2
End
If
' Determine the number of settings.
Settings = CurrentSettings.LocalUris.Length - 1
' Randomize the settings.
Randomize(DateTime.Now.Millisecond)
Selection = Convert.ToInt32(Settings * Rnd())
' Obtain the style and location.
' Choose the wallpaper style.
Select
Case
CurrentSettings.LocalUris(Selection).Style
Case
WinWallpaper.Styles.Stretched
Wallpaper.Style = WinWallpaper.Styles.Stretched
Case
WinWallpaper.Styles.Centered
Wallpaper.Style = WinWallpaper.Styles.Centered
Case
WinWallpaper.Styles.Tiled
Wallpaper.Style = WinWallpaper.Styles.Tiled
' Add the Windows 7 and above-specific options.
Case
WinWallpaper.Styles.Fit
Wallpaper.Style = WinWallpaper.Styles.Fit
Case
WinWallpaper.Styles.Fill
Wallpaper.Style = WinWallpaper.Styles.Fill
End
Select
' Create a wallpaper URI.
NewUri =
New
Uri(CurrentSettings.LocalUris(Selection).Location)
' Set the wallpaper location.
Wallpaper.WallpaperURI = NewUri
ElseIf
CurrentSettings.RemoteChecked
Then
' Detect configuration errors.
If
CurrentSettings.RemoteUris
Is
Nothing
Then
MessageBox.Show(
"Application not set up "
+ _
"to use remote locations."
)
Return
-2
End
If
' Determine the number of settings.
Settings = CurrentSettings.RemoteUris.Length - 1
' Randomize the settings.
Randomize(DateTime.Now.Millisecond)
Selection = Convert.ToInt32(Settings * Rnd())
' Obtain the style and location.
' Choose the wallpaper style.
Select
Case
CurrentSettings.RemoteUris(Selection).Style
Case
WinWallpaper.Styles.Stretched
Wallpaper.Style = WinWallpaper.Styles.Stretched
Case
WinWallpaper.Styles.Centered
Wallpaper.Style = WinWallpaper.Styles.Centered
Case
WinWallpaper.Styles.Tiled
Wallpaper.Style = WinWallpaper.Styles.Tiled
' Add the Windows 7 and above-specific options.
Case
WinWallpaper.Styles.Fit
Wallpaper.Style = WinWallpaper.Styles.Fit
Case
WinWallpaper.Styles.Fill
Wallpaper.Style = WinWallpaper.Styles.Fill
End
Select
' Create a wallpaper URI.
NewUri =
New
Uri(CurrentSettings.RemoteUris(Selection).Location)
' Set the wallpaper location.
Wallpaper.WallpaperURI = NewUri
Else
MessageBox.Show(
"None of the random settings are selected."
)
End
If
Return
0
End
If
All of the Windows 7 additions are marked with comments. The code simply ensures that the stored settings are handled appropriately. There isn’t any change in command line syntax or behavior with these changes.
Modifying frmMain
The majority of the changes for this update appear in frmMain. The only way to accomplish the task is to go through the code one step at a time. The first change appears in frmMain_Load(), which was originally discussed in Exploring the GrabAPicture Application (Part 10). The Select statement needs to be updated to ensure that the form loads with the controls configured correctly as shown here.
' Get the current wallpaper style.
Select
Case
Wallpaper.Style
Case
WinWallpaper.Styles.Stretched
rbStretched.Checked =
True
rbCentered.Checked =
False
rbTiled.Checked =
False
rbFit.Checked =
False
rbFill.Checked =
False
Case
WinWallpaper.Styles.Centered
rbStretched.Checked =
False
rbCentered.Checked =
True
rbTiled.Checked =
False
rbFit.Checked =
False
rbFill.Checked =
False
Case
WinWallpaper.Styles.Tiled
rbStretched.Checked =
False
rbCentered.Checked =
False
rbTiled.Checked =
True
rbFit.Checked =
False
rbFill.Checked =
False
Case
WinWallpaper.Styles.Fit
rbStretched.Checked =
False
rbCentered.Checked =
False
rbTiled.Checked =
False
rbFit.Checked =
True
rbFill.Checked =
False
Case
WinWallpaper.Styles.Fill
rbStretched.Checked =
False
rbCentered.Checked =
False
rbTiled.Checked =
False
rbFit.Checked =
False
rbFill.Checked =
True
End
Select
You must also add event handlers for the Fit and Fill radio buttons on frmMain. These event handlers as similar to those discussed for the other radio buttons as shown here.
Private
Sub
rbFit_CheckedChanged(sender
As
System.
Object
, _
e
As
System.EventArgs) _
Handles
rbFit.CheckedChanged
Dim
Wallpaper
As
New
WinWallpaper
' Set the new style.
Wallpaper.Style = WinWallpaper.Styles.Fit
End
Sub
Private
Sub
rbFill_CheckedChanged(sender
As
System.
Object
, _
e
As
System.EventArgs) _
Handles
rbFill.CheckedChanged
Dim
Wallpaper
As
New
WinWallpaper
' Set the new style.
Wallpaper.Style = WinWallpaper.Styles.Fill
End
Sub
Modifying frmConfigure
The two Select buttons on frmConfigure (discussed in the Exploring the GrabAPicture Application (Part 11) post) require modification to work with the new options. When a user clicks Select, the code configures the Desktop with the newly selected wallpaper. The updates merely make it possible for the configured sources to contain the new fit and fill options. The code for the local resources version of the Select button appears here.
Private
Sub
btnLSelect_Click(
ByVal
sender
As
System.
Object
, _
ByVal
e
As
System.EventArgs) _
Handles
btnLSelect.Click
' Wallpaper manipulation class.
Dim
Wallpaper
As
New
WinWallpaper
' Choose the wallpaper style.
Select
Case
CurrentSettings.LocalUris(lstLocal.SelectedIndex).Style
Case
WinWallpaper.Styles.Stretched
Wallpaper.Style = WinWallpaper.Styles.Stretched
Case
WinWallpaper.Styles.Centered
Wallpaper.Style = WinWallpaper.Styles.Centered
Case
WinWallpaper.Styles.Tiled
Wallpaper.Style = WinWallpaper.Styles.Tiled
' Add the Windows 7 and above-specific Styles.
Case
WinWallpaper.Styles.Fit
Wallpaper.Style = WinWallpaper.Styles.Fit
Case
WinWallpaper.Styles.Fill
Wallpaper.Style = WinWallpaper.Styles.Fill
End
Select
' Create a wallpaper URI.
Dim
NewUri
As
New
Uri( _
CurrentSettings.LocalUris(lstLocal.SelectedIndex).Location)
' Set the wallpaper location.
Wallpaper.WallpaperURI = NewUri
End
Sub
The remote version of the Select button code appears here.
Private
Sub
btnSelect_Click(
ByVal
sender
As
System.
Object
, _
ByVal
e
As
System.EventArgs) _
Handles
btnSelect.Click
' Wallpaper manipulation class.
Dim
Wallpaper
As
New
WinWallpaper
' Choose the wallpaper style.
Select
Case
CurrentSettings.RemoteUris(lstRemote.SelectedIndex).Style
Case
WinWallpaper.Styles.Stretched
Wallpaper.Style = WinWallpaper.Styles.Stretched
Case
WinWallpaper.Styles.Centered
Wallpaper.Style = WinWallpaper.Styles.Centered
Case
WinWallpaper.Styles.Tiled
Wallpaper.Style = WinWallpaper.Styles.Tiled
' Add the Windows 7 and above-specific Styles.
Case
WinWallpaper.Styles.Fit
Wallpaper.Style = WinWallpaper.Styles.Fit
Case
WinWallpaper.Styles.Fill
Wallpaper.Style = WinWallpaper.Styles.Fill
End
Select
' Create a wallpaper URI.
Dim
NewUri
As
New
Uri( _
CurrentSettings.RemoteUris(lstRemote.SelectedIndex).Location)
' Set the wallpaper location.
Wallpaper.WallpaperURI = NewUri
End
Sub
Modifying frmAddEdit
The final set of changes for this update is to frmAddEdit, which is discussed in the Exploring the GrabAPicture Application (Part 12) post. It’s important to remember that unlike frmMain, the radio buttons on this form don’t have any event handlers. The settings are handled in a different way in the code. The first set of changes appear in frmAddEdit_Load() to ensure that the form is configured correctly when the user opens it as shown here.
' Set the form up for editing.
If
_IsEdit
Then
' Make sure you use the correct database.
If
_IsRemote
Then
txtName.Text = _RemoteSources(_RecordNumber).Name
txtLocation.Text = _RemoteSources(_RecordNumber).Location
Select
Case
_RemoteSources(_RecordNumber).Style
Case
Styles.Stretched
rbStretched.Checked =
True
rbCentered.Checked =
False
rbTiled.Checked =
False
rbFit.Checked =
False
rbFill.Checked =
False
Case
Styles.Centered
rbStretched.Checked =
False
rbCentered.Checked =
True
rbTiled.Checked =
False
rbFit.Checked =
False
rbFill.Checked =
False
Case
Styles.Tiled
rbStretched.Checked =
False
rbCentered.Checked =
False
rbTiled.Checked =
True
rbFit.Checked =
False
rbFill.Checked =
False
Case
Styles.Fit
rbStretched.Checked =
False
rbCentered.Checked =
False
rbTiled.Checked =
False
rbFit.Checked =
True
rbFill.Checked =
False
Case
Styles.Fill
rbStretched.Checked =
False
rbCentered.Checked =
False
rbTiled.Checked =
False
rbFit.Checked =
False
rbFill.Checked =
True
End
Select
Else
txtName.Text = _Resources(_RecordNumber).Name
txtLocation.Text = _Resources(_RecordNumber).Location
Select
Case
_Resources(_RecordNumber).Style
Case
Styles.Stretched
rbStretched.Checked =
True
rbCentered.Checked =
False
rbTiled.Checked =
False
rbFit.Checked =
False
rbFill.Checked =
False
Case
Styles.Centered
rbStretched.Checked =
False
rbCentered.Checked =
True
rbTiled.Checked =
False
rbFit.Checked =
False
rbFill.Checked =
False
Case
Styles.Tiled
rbStretched.Checked =
False
rbCentered.Checked =
False
rbTiled.Checked =
True
rbFit.Checked =
False
rbFill.Checked =
False
Case
Styles.Fit
rbStretched.Checked =
False
rbCentered.Checked =
False
rbTiled.Checked =
False
rbFit.Checked =
True
rbFill.Checked =
False
Case
Styles.Fill
rbStretched.Checked =
False
rbCentered.Checked =
False
rbTiled.Checked =
False
rbFit.Checked =
False
rbFill.Checked =
True
End
Select
End
If
End
If
The second set of changes occurs in the btnAddEdit_Click() event handler, which determines what happens to the user selections when the user closes the form (no matter what the button caption might say at the time). Here are the changes for this event handler.
Private
Sub
btnAddEdit_Click(
ByVal
sender
As
System.
Object
, _
ByVal
e
As
System.EventArgs) _
Handles
btnAddEdit.Click
If
IsEdit
Then
If
_IsRemote
Then
' Change the array data.
_RemoteSources(_RecordNumber).Name = txtName.Text
_RemoteSources(_RecordNumber).Location = txtLocation.Text
If
rbStretched.Checked
Then
_RemoteSources(_RecordNumber).Style = Styles.Stretched
End
If
If
rbCentered.Checked
Then
_RemoteSources(_RecordNumber).Style = Styles.Centered
End
If
If
rbTiled.Checked
Then
_RemoteSources(_RecordNumber).Style = Styles.Tiled
End
If
' Add the Windows 7 and above-specific options.
If
rbFit.Checked
Then
_RemoteSources(_RecordNumber).Style = Styles.Fit
End
If
If
rbFill.Checked
Then
_RemoteSources(_RecordNumber).Style = Styles.Fill
End
If
Else
' Change the array data.
_Resources(_RecordNumber).Name = txtName.Text
_Resources(_RecordNumber).Location = txtLocation.Text
If
rbStretched.Checked
Then
_Resources(_RecordNumber).Style = Styles.Stretched
End
If
If
rbCentered.Checked
Then
_Resources(_RecordNumber).Style = Styles.Centered
End
If
If
rbTiled.Checked
Then
_Resources(_RecordNumber).Style = Styles.Tiled
End
If
' Add the Windows 7 and above-specific options.
If
rbFit.Checked
Then
_Resources(_RecordNumber).Style = Styles.Fit
End
If
If
rbFill.Checked
Then
_Resources(_RecordNumber).Style = Styles.Fill
End
If
End
If
Else
If
_IsRemote
Then
' Add a new array element.
If
_RemoteSources
Is
Nothing
Then
ReDim
_RemoteSources(0)
Else
ReDim
Preserve
_RemoteSources(_RemoteSources.Length)
End
If
' Instantiate a new array item.
_RemoteSources(_RemoteSources.Length - 1) =
New
RemoteUri
' Add the data to the array.
_RemoteSources(_RemoteSources.Length - 1).Name = txtName.Text
_RemoteSources(_RemoteSources.Length - 1).Location = txtLocation.Text
If
rbStretched.Checked
Then
_RemoteSources(_RemoteSources.Length - 1).Style = Styles.Stretched
End
If
If
rbCentered.Checked
Then
_RemoteSources(_RemoteSources.Length - 1).Style = Styles.Centered
End
If
If
rbTiled.Checked
Then
_RemoteSources(_RemoteSources.Length - 1).Style = Styles.Tiled
End
If
' Add the Windows 7 and above-specific options.
If
rbFit.Checked
Then
_RemoteSources(_RemoteSources.Length - 1).Style = Styles.Fit
End
If
If
rbFill.Checked
Then
_RemoteSources(_RemoteSources.Length - 1).Style = Styles.Fill
End
If
Else
' Add a new array element.
If
_Resources
Is
Nothing
Then
ReDim
_Resources(0)
Else
ReDim
Preserve
_Resources(_Resources.Length)
End
If
' Instantiate a new array item.
_Resources(_Resources.Length - 1) =
New
LocalUri
' Add the data to the array.
_Resources(_Resources.Length - 1).Name = txtName.Text
_Resources(_Resources.Length - 1).Location = txtLocation.Text
If
rbStretched.Checked
Then
_Resources(_Resources.Length - 1).Style = Styles.Stretched
End
If
If
rbCentered.Checked
Then
_Resources(_Resources.Length - 1).Style = Styles.Centered
End
If
If
rbTiled.Checked
Then
_Resources(_Resources.Length - 1).Style = Styles.Tiled
End
If
' Add the Windows 7 and above-specific options.
If
rbFit.Checked
Then
_Resources(_Resources.Length - 1).Style = Styles.Fit
End
If
If
rbFill.Checked
Then
_Resources(_Resources.Length - 1).Style = Styles.Fill
End
If
End
If
End
If
End
Sub
As you can see, the new options work precisely the same as the existing ones. When the user adds or edits a local or remote wallpaper, the code makes the appropriate changes to the stored settings.
If you compile your application at this point, you’ll find that you can now work with the Fit and Fill wallpaper settings in Windows 7. These settings will also be available when you move your application to Windows 8. All of these code changes come down to one thing really. The new settings involve additions to the WallpaperStyle registry settings: 6 for Fit and 10 for Fill. Let me know if you have any questions about these changes at John@JohnMuellerBooks.com.