Improving the GrabAPicture Application (Part 2)

Just before the year ended, I discussed some additions you might want to make to the GrabAPicture application in the Improving the GrabAPicture Application (Part 1) post. One of those additions is allowing the user to modify the application configuration from the command line, rather than use the GUI to do it. Configuration modification is a common application requirement and any application that administrators have to support should have a command line option to make these modifications. You don’t have to provide access to absolutely every configuration option, but you should provide access to the most common configuration options. The options you support in your application is determined by:

 

  • Administrator configuration needs: The administrator may be able to provide input on precisely which tasks the application will need to perform remotely. Remote tasks are usually good candidates for command line support.

  • Application complexity: When working with a simple application, you have the luxury of including all of the configuration options at the command line. As applications become more complex, you must pick and choose command line features. Using multiple levels of command line switches also becomes a requirement. As an example, look at the WMIC command line utility.
  • Application type: The tasks that the application performs partially dictate the command line interface. An application designed for management tasks (such as WMIC) will require a more robust command line than one used for localized data handling (such as Notepad).


For the GrabAPicture application, the main consideration is application complexity. There are only two configuration settings, so the command line will support both of them. Of course, you have multiple options for adding the command line switches. Because the interface is relatively simple, we’ll change the command line arguments so they appear like this:

GrabAPicture
GrabAPicture /?
GrabAPicture /Random
GrabAPicture /Picture:<Picture URI> [/Style:Stretched | Centered | Tiled]
GrabAPicture /Configure [/Local:[True | False]] [/Remote:[True | False]]

The new option, /Configure, displays the current configuration when used alone. Adding the /Local command line switch changes the Use Random Local Sources setting, while adding the /Remote command line switch changes the Use Random Remote Sources setting.

At this point, you can add the required functionality. Modifying the code is a three-step process:

 

  • Change the help information.
  • Add the configuration code.
  • Add the frmMain-specific code required to perform tasks.


With these steps in mind, lets begin with the help information. The following listing shows the updated help code in bold.

' 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)
   Output.Append("GrabAPicture /Configure " + _
                 "[/Local:[True | False]] " + _
                 "[/Remote:[True | False]]" + 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)
   Output.Append("/Configure - Provides a means of discovering the " + _
                 "configuration when used alone or modifying the " + _
                 "configuration when used with the /Local and/or " + _
                 "/Remote command line switches." + vbCrLf)
   Output.Append("/Local - Sets the application to use local random " + _
                 "sources when set to True." + vbCrLf)
   Output.Append("/Remote - Sets the application to use remote random " + _
                 "sources when set to True." + vbCrLf)
 
   ' Display the help.
   MessageBox.Show(Output.ToString(),
                   "GrabAPicture Usage",
                   MessageBoxButtons.OK,
                   MessageBoxIcon.Information)
   Return 0
End If

As you can see, the updated code simply adds more help information to the existing help. The new help screen looks like this:

GrabAPictureUpdate0201

Now it’s time to add the code required to make the new switches work. This code appears directly before the /Picture command line switch code (the line that begins If CmdArg.Length > 8 Then in the Main() function):

' Work with the application configuration.
If CmdArg.ToUpper() = "/CONFIGURATION" Then
 
   ' Determine whether the user wants to see just the configuration
   ' information.
   If CmdArgs.Length = 1 Then
 
      ' Obtain the current settings.
      Dim CurrentSettings As GrabAPictureSettings
      CurrentSettings = GrabAPictureSettings.LoadSettings()
 
      ' Check to make sure there are settings to use.
      If CurrentSettings Is Nothing Then
 
         ' Tell the user there are no settings to display.
         MessageBox.Show("No Settings to Show!",
                         "Configuration Error",
                         MessageBoxButtons.OK,
                         MessageBoxIcon.Error)
         Return -2
      End If
 
      ' Display the settings information.
      MessageBox.Show("Local: " + CurrentSettings.LocalChecked.ToString() + _
                      vbCrLf + "Remote: " + _
                      CurrentSettings.RemoteChecked.ToString(),
                      "GrabAPicture Configuration Settings",
                      MessageBoxButtons.OK,
                      MessageBoxIcon.Information)
      Return 0
 
      ' There must be at least one settings argument.
   Else
      ' Create a variable to hold the current argument.
      Dim SettingArg As String()
 
      ' Create a varible to hold the new value.
      Dim NewValue As Boolean
 
      ' Obtain the current settings.
      Dim CurrentSettings As GrabAPictureSettings
      CurrentSettings = GrabAPictureSettings.LoadSettings()
 
      ' If there aren't any settings.
      If CurrentSettings Is Nothing Then
 
         ' Define default settings.
         CurrentSettings = New GrabAPictureSettings
      End If
 
      ' Process each settings argument in turn.
      For ArgNum As Int32 = 1 To CmdArgs.Length - 1
 
         ' Obtain the switch and argument.
         SettingArg = CmdArgs(ArgNum).Split(":")
 
         ' Verify that the user has actually included a value.
         If Not SettingArg.Length = 2 Then
            MessageBox.Show("You must provide the /Local or /Remote " + _
                            "command line switch followed by a colon (:), " + _
                            "followed by either True or False, such " + _
                            "as /Local:True or /Remote:True",
                            "Argument Error",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error)
            Return -3
         End If
 
         ' Check for a local setting.
         If SettingArg(0).ToUpper() = "/LOCAL" Then
 
            ' Check the setting.
            If Boolean.TryParse(SettingArg(1), NewValue) Then
 
               ' Change the setting.
               CurrentSettings.LocalChecked = NewValue
            End If
 
            ' Save the setting.
            GrabAPictureSettings.SaveSettings(CurrentSettings)
         End If
 
         ' Check for a remote setting.
         If SettingArg(0).ToUpper() = "/REMOTE" Then
 
            ' Check the setting.
            If Boolean.TryParse(SettingArg(1), NewValue) Then
 
               ' Change the setting.
               CurrentSettings.RemoteChecked = NewValue
            End If
 
            ' Save the setting.
            GrabAPictureSettings.SaveSettings(CurrentSettings)
         End If
      Next
   End If
 
   Return 0
End If

This code begins by checking for the /Configuration command line switch. If the user has included it, then the code checks the number of command line arguments. When there is just one argument, the user has used the /Configuration command line switch alone, so the application displays the current configuration information. In order to perform this task, the code must create a GrabAPictureSettings object, CurrentSettings, and load the settings into it. At this point, displaying the information is simply a matter of accessing the current information in CurrentSettings. Make sure you convert the Boolean values to strings.

Setting the configuration is only a little harder. The first thing to consider is that you don’t know whether the user has included just the /Local or /Remote command line switches, or both of them. In addition, you have no idea of which order the user has used for the switches. As a consequence, this application relies on a For loop that doesn’t assume anything. It simply grabs the first switch and then processes it.

The command line switch is supposed to be followed by a colon (:) and then a value. Unfortunately, the user could provide anything as input. The code begins by verifying that the user has provided a switch and value combination (or at least the right number of arguments). It then checks for either /Local or /Remote. The value could still be incorrect, so the application uses the Boolean.TryParse() method to convert the input to a Boolean value safely. If everything works out correctly, the application makes the setting change and saves the result to disk by calling GrabAPictureSettings.SaveSettings(CurrentSettings).

With these changes, the application can now set the configuration from the command line. Next week you’ll see another new addition. In the meantime, let me know if you have any questions about this update at John@JohnMuellerBooks.com.

Author: John

John Mueller is a freelance author and technical editor. He has writing in his blood, having produced 99 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 books include a Web security book, discussions of how to manage big data using data science, a Windows command -line reference, and a book that shows how to build your own custom PC. His technical editing skills have helped over more than 67 authors refine the content of their manuscripts. John has provided technical editing services to both Data Based Advisor and Coast Compute magazines. He has also contributed articles to magazines such as Software Quality Connection, DevSource, InformIT, SQL Server Professional, Visual C++ Developer, Hard Core Visual Basic, asp.netPRO, Software Test and Performance, and Visual Basic Developer. Be sure to read John’s blog at http://blog.johnmuellerbooks.com/. When John isn’t working at the computer, you can find him outside in the garden, cutting wood, or generally enjoying nature. John also likes making wine and knitting. When not occupied with anything else, he makes glycerin soap and candles, which comes in handy for gift baskets. You can reach John on the Internet at John@JohnMuellerBooks.com. John is also setting up a website at http://www.johnmuellerbooks.com/. Feel free to take a look and make suggestions on how he can improve it.