Understanding the CompressedFolder Class

In my last series I showed you how to create a custom object class in VBScript that could create compressed files natively. The intent was to demonstrate how to create and use the class rather than to explain the coding concepts. I decided to revisit the topic for a more thorough explanation.

If you haven’t already, you should read my article about Compressed Folders.  It will provide a little more insight into the code we’ll be examining today.

First let me explain my theory behind this object class.  I wanted an object that would represent a compressed folder (or zip file).  Much like the FileSystemObject’s or Shell Object’s Folder objects, I wanted my object to have a series of methods for adding and removing files, along with properties that would describe the file itself.  In retrospect, I would have liked to add a size property that would display the compressed folder’s size on disk.  Perhaps I’ll put that on my to-do list for the next revision.

Once I had the concept, I made a quick list of the properties and methods that I would like my object to have.  This is a good way to get your code class headed in the right direction.  By making this list, you are able to organize your thoughts better.  You can see how your various properties and methods relate and what outside objects are required, among other things.  This can often help in coding the class itself, as you will have a much broader view of the code you’ll need to accomplish each of your tasks.  Remember that a code class is more than a script; it’s a small project in and of itself.

Once I had the concept on paper, I was able to determine all of my prerequisites.  I knew that I needed the Shell object (along with an ADODB Stream) to create and manipulate compressed folders.  In order to implement some error handling, I’d need to check that files exist as well.  This is most easily done using the FileSystemObject.  It was important to me that I avoided using any objects that weren’t native to the scripting engine.  I also wanted to avoid diving into complicated WMI code, so I was off to a very good start.

{mospagebreak title=Examining the Properties}

My CompressedFolder class needed to have a few basic properties.  I wanted to form them to resemble the properties used by the FileSystemObject’s own Folder object.  I figured this would be the most intuitive way to create my object, by making it easier for users in the end.  Here’s a snapshot of the code I used to create the properties.

   Public Property Get FullName

       FullName = m_fileName  

   End Property

 

   Private Property Let FullName(strName)

       m_fileName = strName

   End Property

 

   Public Property Get Filename

       Filename = Right(FullName, Len(FullName) – InStrRev(FullName, ""))

   End Property

 

   Public Property Get Path

       Path = Left(FullName, InStrRev(FullName, ""))

   End Property

 

   Public Property Get Count

       Count = GetItemCount(FullName)

   End Property

As you can see, there are four different properties available: FullName, Filename, Path, and Count.  The first three all deal with the path and filename of the compressed folder, and the last returns the number of items in the compressed folder.

I wanted to provide these specific properties to make coding with my object easier for the programmer.

Since the first three properties were closely related, I decided to code them together, building each one off of the next.  This eliminated extraneous calls to outside objects, which should hopefully increase my class’s performance.  In this case, a few simple string manipulations are also less complicated than second and third calls to the FileSystemObject for each of the subsequent properties.

{mospagebreak title=More on Properties}

Of my first three properties, the FullName (path and filename to the compressed folder) was the easiest to do first.  This needed to be a user-provided value.  The class user would need to indicate what compressed folder to create or open.  Very simply, this property would assign or retrieve an internal variable that contained the user’s supplied path and filename.

The Filename and Path properties would be easy to code once the value of the FullName property had been assigned, since they are just pieces of that same string.  A little clever use of some string functions would parse out the pieces that I needed.  Remember, your code blocks don’t need to be fancy, just functional.  This simplest and most direct approach is usually the easiest and most efficient.

   Public Property Get Filename

       Filename = Right(FullName, Len(FullName) – InStrRev(FullName, ""))

   End Property

 

   Public Property Get Path

       Path = Left(FullName, InStrRev(FullName, ""))

   End Property

For the Filename property, I simply found the last forward slash in the string returned by the FullName property and grabbed everything to the right of it.  According to standard Windows file naming conventions, this would be the folder or file name.

Another revision might include an update that would prevent an extra forward slash at the end of the full path.  I chose to omit this for simplicity, and because compressed folders already contain a .zip extension indicating a file path rather than a folder path.

The Path property should return the path to the compressed folder.  Here again I can look for the last forward slash in the string returned by the FullName property, this time grabbing everything to the left of it instead.  Essentially, this is the FullName value minus the Filename portion—the exact opposite of the last property.

You might also notice that none of these properties allow public assignment.  Filename and Path are read-only, since they are dependent upon the value of the FullName property, and although the FullName property requires a user-submitted value, I’ve elected to not allow users to set this value directly.  It didn’t seem necessary to have my users supply a property and then call a method, when I could just as easily do everything in a single step without seeming complicated.

Instead of assigning the FullName property directly, the property value is set by the Open method.  This also provided a convenient opportunity for me to do some error handling without having too much code inside of my property statements.

In my opinion, Property blocks are for assigning and retrieving property values.  Any extraneous code belongs in a method of its own.  Code appears neater that way, and it provides a more modularized approach.

{mospagebreak title=Examining the Exposed Methods}

The CompressedFolder class has quite a few methods.  They break down into three groups: exposed methods, internal methods, and support methods.  The exposed methods are the public methods exposed by the class object.  These simply point to methods in the second group.  The internal methods are the ones that perform the actual work of creating the folder, adding and extracting files, and so forth.  The last group is the support methods.  These are the extra functions and subroutines that are used by the internal methods.

Public Sub Open(strFile)

   FullName = strFile

End Sub

 

Public Sub Create(strFile)

   If objFso.FileExists(strFile) Then objFso.DeleteFile(strFile)

   FullName = strFile

   NewCompressedFolder FullName

End Sub

 

Public Sub Add(strFile, blnKeepOriginal)

   AddFile FullName, strFile, blnKeepOriginal

End Sub

 

Public Sub AddMultiple(varSource, blnKeepOriginal)

   AddFiles FullName, varSource, blnKeepOriginal

End Sub

 

Public Sub Extract(strFolder)

   ExtractAll FullName, strFolder

End Sub

Here is the first group of publicly exposed methods.  You can see that these methods simply accept user input and use it to call another internal method.  This is a good coding practice for a couple of reasons, but in my case there was one reason that really stood out.

I wanted to be able to control functionality using the class object’s properties.  Since most of these properties would at some point be used as parameters for my methods, I created a simple public method with pertinent parameters, and then passed them along with the others to my internal methods.  In this way, even though an internal method might have three or four required parameters, the user will only need to supply one or two in their code.  The rest would be predetermined by the object’s properties.

While you won’t see very extensive use of this practice in this code class, I did want to leave that flexibility in place for demonstration purposes, as well as for future upgrades.  I have several additional features that I plan on adding to this class in the future.

Unfortunately, I’m out of space for this article.  So far you’ve seen all of the parts that are exposed through the class’s object.  Be sure to stop back for part two of this series to see the continued explanation of this class.  In my next article, we’ll be examining the internal methods used by this class, as well as its implementation.  Until next time, keep coding!

[gp-comments width="770" linklove="off" ]