Exploring the GrabAPicture Application (Part 9)

In the previous post, Exploring the GrabAPicture Application (Part 8), you saw how all of the GrabAPicture application settings are put together and stored on disk from a low level perspective. This post diverges from the topic of data for a while to consider the user interface that relies on the data. In this case, you discover how the command line interface for this application works. Of course, the first requirement is deciding why the application needs a command line interface. In order to support automatic desktop wallpaper changes, the application does indeed use a command line interface. You can use the command line interface to create a shortcut like the one shown here and add it to the Shortcut folder on your system.

GrabAPicture0901

Look at the Target field. The application is configured to use the /Random command line switch to display any of the configured wallpapers at random. You can configure GrabAPicture in other ways, such as selecting a specific wallpaper. As with most applications that sport a command line interface, GrabAPicture provides a full help screen. The command line interface for this application is as follows:

GrabAPicture /?

GrabAPicture /Random

GrapAPicture /Picture:<Picture URI> [/Style:Stretched | Tiled | Centered]

where:

 

  • /?: Displays the help screen.
  • /Random: Selects any of the configured wallpapers at random.
  • /Picture: Displays a specific graphic found at the specified URI.
  • /Style: Configures Windows to display the wallpaper in Stretched, Tiled, or Centered mode.

Many applications have a considerably more complex command line interface, but you’ll find that this one is more than complex enough. The command line interface resides in frmMain.vb in the Main() function. When you see the code for this part of the example your first thought will be that the code is overly complicated and you’ll never understand it, but this isn’t the case. The Main() function does have a number of decisions to make, but they really come down to a number of selections.

 

  1. If there aren’t any command line arguments, the start the GUI version of the application.
  2. If the user has entered the /? command line switch as the first argument (regardless of anything that follows), display the help screen.
  3. If the user has entered the /Picture command line argument, then process the specific picture.
    1. Obtain the specific URI as the second part of the first command line argument.
    2. Check for a /Style command line switch as a second command line argument.
    3. Obtain the specific style as the second part of the second command line argument.
    4. Display the graphic on screen.
  4. If the user has entered the /Random command line switch, determine which picture to use from the preconfigured selections.
    1. Check for a configuration file. If none exists, display an error message and exit.
    2. If the user has checked both local and remote options, make sure the configuration settings are usable, then obtain a wallpaper selection from the preconfigured choices.
    3. If the user has checked just the local option, make sure there are local wallpaper selections to use, and then obtain the wallpaper selection from the local choices.
    4. If the user has checked just the remote option, make sure there are remote wallpaper selections to use, and then obtain the wallpaper selection from the remote choices.
    5. When the user hasn’t selected either local or remote random selections, display an error message and exit.

That’s really all there is to the code—a number of choices. With that in mind, here’s the massive looking, but not all that difficult code for this part of the example (normally, I don’t present code segments this long, but this particular example requires that I show the entire segment so you can see how it works).

Shared Function Main(ByVal CmdArgs() As String) As Integer
   ' Process the command line arguments.
   If CmdArgs.Length > 0 Then
      ' Get the first argument.
      Dim CmdArg As String = CmdArgs(0)
 
      ' User is requesting help.
      If CmdArg = "/?" Then
         ' Create an output string.
         Dim Output As New StringBuilder
 
         ' Create the usage instructions.
         Output.Append("Usage:" + vbCrLf)
         Output.Append("GrabAPicture" + vbCrLf)
         Output.Append("GrabAPicture /?" + vbCrLf)
         Output.Append("GrabAPicture /Random" + vbCrLf)
         Output.Append("GrabAPicture /Picture:<Picture URI> " + _
                       "[/Style:Stretched | Centered | Tiled]" + _
                       vbCrLf + vbCrLf)
         Output.Append("When used alone, displays the configuration " + _
                       "interface" + vbCrLf)
         Output.Append("/? - Displays this help message." + vbCrLf)
         Output.Append("/Random - Displays one of the images provided as " + _
                       "random input through the configuration program." + _
                       vbCrLf)
         Output.Append("/Picture - Defines a local or Web location for a " + _
                       "picture." + vbCrLf)
         Output.Append("/Style - Determines the display style of the " + _
                       "picture. Use only with the /Picture switch." + vbCrLf)
 
         ' Display the help.
         MessageBox.Show(Output.ToString(),
                         "GrabAPicture Usage",
                         MessageBoxButtons.OK,
                         MessageBoxIcon.Information)
         Return 0
      End If
 
      ' User wants to display a particular picture.
      If CmdArg.Length > 8 Then
         If CmdArg.Substring(0, 8).ToUpper() = "/PICTURE" Then
 
            ' Wallpaper manipulation class.
            Dim Wallpaper As New WinWallpaper
 
            ' Split the string.
            Dim NewUri As Uri
            NewUri = New Uri(CmdArg.Substring(9))
 
            ' Determine whether there is a Style argument to process.
            If CmdArgs.Length > 1 Then
 
               ' Get the style argument.
               Dim StyleArg As String = CmdArgs(1)
 
               ' Change the style.
               If StyleArg.Substring(0, 6).ToUpper() = "/STYLE" Then
                  Select Case StyleArg.Substring(7).ToUpper()
                     Case "STRETCHED"
                        Wallpaper.Style = WinWallpaper.Styles.Stretched
                     Case "CENTERED"
                        Wallpaper.Style = WinWallpaper.Styles.Centered
                     Case "TILED"
                        Wallpaper.Style = WinWallpaper.Styles.Tiled
                  End Select
               End If
            End If
 
            ' Change the wallpaper.
            Wallpaper.WallpaperURI = NewUri
         End If
         Return 0
      End If
 
      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
               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
               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
            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
            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
 
      ' Indicate an error condition for the command
      ' line switches.
      MessageBox.Show( _
         "Use the /? switch to see application usage.", _
         "GrabAPicture", _
         MessageBoxButtons.OK, _
         MessageBoxIcon.Error)
      Return -1
   Else
      ' Run the application for configuration purposes.
      Application.Run(New frmMain)
   End If
End Function

The Main() function begins by checking CmdArgs.Length, which contains the number of command line arguments passed from the command line by the user. When this value is 0, the example bypasses all of the rest of that command line processing code and calls the standard code, Application.Run(New frmMain).

Of course, you’re interested in finding out what happens when the user does provide a command line argument. The first thing you’ll normally check is the /? command line switch. In this case, all it does is create a StringBuilder object, Output, and display it to the user. Unlike most command line utilities, which display help screen at the command prompt, GrabAPicture does use a dialog box like the one shown here to display help.

GrabAPicture0902

Because Main() is a function, you need to return some sort of value that indicates success or failure. If you always return 0, then the utility isn’t very useful in a batch file. The example returns a value of 0 to indicate success. However, it uses other values to indicate errors:

 

  • -1: The application hasn’t been configured to use random sources.
  • -2: The application hasn’t been configured to use both local and/or remote random sources.

You can actually test for these errors in a batch file and then do something about it. Yes, batch files do offer limited capabilities for error trapping and even fewer options for recovery, but these outputs do provide the opportunity recover in at least some cases.

The next test is against a word, Picture, which can be in any case. Whether you use uppercase or lowercase is up to youI happen to prefer uppercase, so the next test looks for /PICTURE. The command line switch is only part of the argument though, so you must extract the switch from the URI of the image the user wants to use by calling CmdArg.Substring(0, 8).

On to the picture processing. The code begins by creating a new WinWallpaper object, Wallpaper. It then creates a Uri object, NewUri, from the second half of the first command line argument using CmdArg.Substring(9). This method skips the colon that separates /Picture from the URI of the picture.

Now, the application has to decide how to display the image. If the user doesn’t supply the /Style command line switch, the application uses whatever setting is in place. Otherwise, the application uses a Select Case block to choose the appropriate style.

Only after the application has done all of this other processing does it set the Wallpaper.WallpaperURI property value. Changing this value changes the wallpaper (see Exploring the GrabAPicture Application (Part 7) for details).

So, what happens with the /Random command line switch? The processing is more straightforward than you might think. There are four possibilities:

 

  • Both the Use Random Local Sources and Use Random Remote Sources check boxes are checked.
  • Only the Use Random Local Sources check box is checked.
  • Only the Use Random Remote Sources check box is checked.
  • Neither check box is checked.

In the last case, the program exits with an error message and an error code. All three other cases follow the same pattern.

 

  1. The application checks for the required resources.
  2. When the settings exist, the application obtains the number of available settings.
  3. The application then selects a random item from the list of available settings.
  4. The code sets the Wallpaper.Style property value.
  5. The code creates a Uri from the settings.
  6. The code sets the Wallpaper.WallpaperURI property value, which changes the wallpaper on the Desktop.

There is one final consideration for this example and you’re bound to miss it in all of that code. The user could enter a command line switch that’s pure gibberish. Users do that. In this case, you need to tell the user how to get help. This little piece of code keeps things from blowing up or frustrating the user.

' Indicate an error condition for the command
' line switches.
MessageBox.Show( _
   "Use the /? switch to see application usage.", _
   "GrabAPicture", _
   MessageBoxButtons.OK, _
   MessageBoxIcon.Error)
Return -1

This is a short course on the command line interface for the GrabAPicture application. If you have any questions about it, please contact me at John@JohnMuellerBooks.com. Next week we’ll look at the code behind the GrabAPicture frmMain controls. You can find the next post in this series at Exploring the GrabAPicture Application (Part 10).

Author: John

John Mueller is a freelance author and technical editor. He has writing in his blood, having produced 117 books and over 600 articles to date. The topics range from networking to artificial intelligence and from database management to heads-down programming. Some of his current offerings include topics on machine learning, AI, Android programming, and C++ programming. His technical editing skills have helped over more than 70 authors refine the content of their manuscripts. You can reach John on the Internet at John@JohnMuellerBooks.com.