Advanced Visual Basic (Visual Studio 2010) - Project 8

Using the CompInfo.dll class library and converting it to a Component Library

Project 8

What’s a Class Library worth without OLE Client applications to use it's exposed functionality?

Nothing . . . almost. In fact, many Class Libraries are also standalone programs.  Ok, let me rephrase that: Many standalone programs are also Class Libraries.  They have EXE extensions and are called OLE Server applications.  Excel, Word, Access, and PowerPoint—just to name a few—are all OLE Server applications.  A pure Class Library is not a standalone application and it has a DLL extension.  In project 7 you created a pure Class Library file (CompInfo.dll).  Without another standalone program—an OLE Client application—to access its classes, it would be useless.

In this project in Part A, you will create a simple OLE Client application for your CompInfo.dll Class Library.  In Part B, you will learn how to convert a Class Library into a Component Library.  We will discuss the differences between a Class Library and a Component Library when you get to part B.

Part A

Creating an OLE Client application for the CompInfo.dll Class Library

Launch Microsoft Visual Studio 2010.  Drop down the File menu and select New Project...

Be sure the Windows Forms Application template in the New Project dialog is selected in the Templates pane on the right side, then type CompInfoTest in the Name textbox (as shown below): 

Now click the OK button. 

Save the project by clicking on the Save All button on the standard toolbar.  This displays the Save Project dialog box, as shown:

Do not change the default Location path.  Be sure to uncheck the Create directory for solution option, as show above, before clicking on the Save button. 

This creates a new folder inside the My Documents\Visual Studio 2010\Projects\  folder named CompInfoTest:

        My Documents\Visual Studio 2010\Projects\CompInfoTest

Rename the Form file

Make sure the form file is selected in the Solution Explorer window:

With the form file (Form1.vb) selected in the Solution Explorer window (as shown above), the Properties window directly below it displays it's File properties.  Click on the File Name property and type frmCompInfoTest.vb and press the enter key (don't forget to include the .vb extension, as shown in the illustration below):

Change the Name and Text properties of the Form

To display the properties of the form in the Properties window, click once on the blank Form, which should be displayed on the left side of the screen in the Design window.  Make sure the Name property—which is in parentheses (Name) at the top of the property list so that it's easy to find—is frmCompInfoTest.  It should have been set to that automatically when we named the form file.  Then scroll the properties windows down—the properties are listed alphabetically—and change the Text property to CompInfo Test as shown below:

Adding a Reference to the CompInfo.dll Class Library

We will begin by adding a Reference to the CompInfo.dll Class Library we created in project 7.  Right-click on the CompInfoTest project in the solution explorer window and select Add Reference from the context menu:

On the Add Reference dialog click on the Browse tab and navigate to the CompInfo\bin\Release folder (as shown below):

Inside the CompInfo\bin\Release folder you should find your CompInfo.dll code library file from the last project:

Select the CompInfo.dll code library file and click the OK button.

Once the reference to the CompInfo.dll file is added to the project, click on the Show All Files button (circled below) at the top of the solution explorer window to display the References folder.  Take a look inside and you should see an entry for CompInfo, as shown:

Using the Object Browser to browse the classes of Class Libraries

To actually see what classes a Class Library contains, we can use the Object Brower.  Click on the Object Browser button on the standard toolbar, as shown:

Click on the + box in front of the CompInfo item at the top of the Objects pane to expand it and see the four classes it contains (as show below):

When you click on a class (for example pCPU, as shown above), any properties, methods or other classes it contains are listed in the Members pane on the right.

Close the Object Browser window when you are finished looking at it.

Creating the CompInfoTest form

The above illustration is an example of the finished application.  We will be constructing this form one GroupBox at a time, and testing it as we go. 

Adding the CPU Information groupbox

Use the illustration above to guide you as you add a GroupBox to the upper left area of the form that contains ten Labels with these property settings. Note: Only the Labels on the right will be referenced in code.  So the labels on the left keep their default names and the labels on the right get descriptive names.  Also, be sure to set the AutoSize property of all the Labels to False, so that you can resize them:

GroupBox
Property Value
Text CPU Information
Property Label Value Property Label Value
Text Count: Name lblCount
TextAlign MiddleRight TextAlign MiddleLeft
Property Label Value Property Label Value
Text Arch: Name lblArchitecture
TextAlign MiddleRight TextAlign MiddleLeft
Property Label Value Property Label Value
Text Level: Name lblLevel
TextAlign MiddleRight TextAlign MiddleLeft
Property Label Value Property Label Value
Text Version: Name lblVersion
TextAlign MiddleRight TextAlign MiddleLeft
Property Label Value Property Label Value
Text Identifier: Name lblIdentifier
TextAlign MiddleRight TextAlign MiddleLeft

Using the Load event procedure to populate the CPU Information labels

Most of the code for this application can go in the form's Load event procedure (frmCompInfoTest_Load).  Add this line of code at the top of the frmCompInfoTest_Load event procedure to construct an instance of a pCPU object:

Dim objCPU As New CompInfo.pCPU()

After typing New and a space, the list of available classes that popped up included our CompInfo Class Library because we had set a Reference to it previously.   Now all we need to do is set the Text property of the named labels in the CPU Information groupbox to the appropriate properties of objCPU.  Add this code to the frmCompInfoTest_Load event procedure:

'Display the CPU Information
lblCount.Text = objCPU.Count
lblArchitecture.
Text = objCPU.Architecture
lblLevel.
Text = objCPU.Level
lblVersion.
Text = objCPU.Version
lblIdentifier.
Text = objCPU.Identifier

Testing the program so far

Save the project now.  Run the program.  Is the CPU Information displayed?

Adding the Memory Information groupbox

Use the illustration above to guide you as you add a GroupBox to the lower left corner of the form that contains four Labels with these property settings. Note: Like before, only the Labels on the right will be referenced in code, so they get descriptive names. Be sure to set the AutoSize property of all the Labels to False, so that you can resize them:

GroupBox
Property Value
Text Memory Information
Property Label Value Property Label Value
Text Free Physical: Name lblFreePhys
TextAlign MiddleRight TextAlign MiddleLeft
Property Label Value Property Label Value
Text Free Virtual: Name lblFreeVirt
TextAlign MiddleRight TextAlign MiddleLeft

Using the Load event procedure to populate the Memory Information labels

Add this line of code at the top of the frmCompInfoTest_Load event procedure to construct an instance of a pMemory object:

Dim objMem As New CompInfo.pMemory()

Recall that the FreePhys, and FreeVirt properties of the pMemory class are String values.  Look at this code for the declaration of the FreePhys property from project 7:

ReadOnly Property FreePhys() As String

The As String specification at the end of this property declaration says that FreePhys returns a String value.  That means that if the amount of free physical memory was 64,394 kilobytes, the value that FreePhys would return would look like this:

64394

To make this number easier to read, let's convert it from kilobytes into megabytes, and add two decimal places to it.  So that the above number would look like this:

64.39

We can use the CDbl conversion function to convert the strings returned by FreePhys and FreeVirt into numbers.  Then we can divide the values by 1024 to convert kilobytes into megabytes.  Finally, the Format function makes it easy to add two decimal places to the number. Add the following code to the frmCompInfoTest_Load event procedure (after the code that sets the values for CPU Information groupbox) :

'Display the Memory Information, converted
'    to megabyte values with 2 decimal places.
lblFreePhys.Text = _
    Format(
CDbl(objMem.FreePhys) / 1024, _
           
"#,##0.00")  & " Megabytes"
lblFreeVirt.Text = _
    Format(
CDbl(objMem.FreeVirt) / 1024, _
           
"#,##0.00")  & " Megabytes"

Testing the program so far

Save the project now.  Run the program.  Is the Memory Information displayed and formatted correctly?

Adding the Operating System Information groupbox

Use the illustration above to guide you as you add a GroupBox to the lower middle of the form that contains four Labels with these property settings. And once more, don't forget to set the AutoSize property of all the Labels to False, so that you can resize them:

GroupBox
Property Value
Text Operating System Information
Property Label Value Property Label Value
Text Platform: Name lblOSPlatform
TextAlign MiddleRight TextAlign MiddleLeft
Property Label Value Property Label Value
Text Version: Name lblOSVersion
TextAlign MiddleRight TextAlign MiddleLeft

Using the Load event procedure to populate the Operating System Information labels

Add this line of code at the top of the frmCompInfoTest_Load event procedure to construct an instance of a pOS object:

Dim objOS As New CompInfo.pOS()

No special formatting is required for the operating system's Platform and Version values, so add the following code to the frmCompInfoTest_Load event procedure (after the code that sets the values for the Memory Information groupbox) :

'Display the Operating System Information
lblOSPlatform.Text = objOS.Platform
lblOSVersion.
Text = objOS.Version

Objects that are constructed within a procedure are usually deconstructed automatically when the procedure exists and they fall out of scope.  But just in case, it's always a good idea to dispose of objects when you are finished using them.  So add the following code to the bottom of the frmCompInfoTest_Load event procedure:

'Deconstruct the pCPU, pMemory,
'    and pOS objects.
objCPU = Nothing
objMem
= Nothing
objOS
= Nothing

By setting an object's reference variable to Nothing, the instance of that object is destroyed.  We can always construct new instances of the objects later if we need them.

Adding the Disk Drive Information groupbox

Use the illustration above to guide you as you add a GroupBox to the upper right corner of the form that contains eight Labels and a ComboBox with these property settings:

GroupBox
Property Value
Text Disk Drive Information
Property Label Value (this space available for lease)
Text Select a Drive
TextAlign MiddleCenter
Property Label Value Property ComboBox Value
Text Drive: Name cboDrives
TextAlign MiddleRight
Property Label Value Property Label Value
Text Size: Name lblSize
TextAlign MiddleRight TextAlign MiddleLeft
Property Label Value Property Label Value
Text Free Space: Name lblFreeSpace
TextAlign MiddleRight TextAlign MiddleLeft
Property Label Value Property Label Value
Text Used Space: Name lblUsedSpace
TextAlign MiddleRight TextAlign MiddleLeft

Using the Load event procedure to populate the Drives combobox

Before we can get information about the drives on the computer, we need to find out what drives are installed.  We can use the GetLogicalDrives method of the System.Environment class to determine what drives are installed on the computer.  GetLogicalDrives returns a string array that contains the drive letters of all the installed drives—one in each element of the array—in this format: <drive letter>:\ or for example: C:\.  We can use a command like this to create and fill a string array named sDrives with the installed drives on the computer:

'Copy the string array returned by the
'    GetLogicalDrives method into the
'    sDrives string array.
Dim sDrives As String() = _
    System.
Environment.GetLogicalDrives()
'Clear the contents of the combobox
'    before filling it.
cboDrives.Items.Clear()

Add the two lines of code above at the end of the frmCompInfoTest_Load event procedure (below the objOS = Nothing line).

Once the sDrives array contains the drive letters of the valid drives on the computer, we need to populate the cboDrives combobox with those values.  We could add the drive letters to the cboDrives combobox like this (don't type this code):

cboDrives.Items.Add(sDrives(0))
cboDrives.
Items.Add(sDrives(1))
cboDrives.
Items.Add(sDrives(2))
etc...

But we don't know how many elements the sDrives array contains!  Unlike a collection, an array variable has no Count property that tells you how many items it contains.  We could use the old fashioned UBound() function to determine the number of elements in the sDrives array, like this (don't type this code):

Dim i As Integer
'The UBound functions returns the index
'    value of the last element in an array.
For i = 0 to UBound(sDrives) - 1
    cboDrives.
Items.Add(sDrives(i))
Next i

But with VB.NET, string variables now have a Length property that returns the total number of elements in the array.  So we could use it instead, like this (don't type this code):

Dim i As Integer
'The Length method returns the total
'    number of elements in an array.
For i = 0 to sDrives.Length() - 1
    cboDrives.
Items.Add(sDrives(i))
Next i

While the two methods I described above would work just fine, there is a third way that we will actually use.  Not because it is better, but because I want you to become more familiar with it.  Instead of a For-Next loop, we will use a For-Each loop.  We actually used For-Each loops twice in project 7 to create the FreePhys, and FreeVirt properties of the pMemory class.   Here is how the For-Each loop version of the code to fill the cboDrives combobox looks:

'Create an sDrive string variable to
'    become each element of the array.
Dim sDrive As String
For Each
sDrive In sDrives
    cboDrives.Items.Add(sDrive)
Next

Add the above code at the end of the frmCompInfoTest_Load event procedure.  With the For-Each loop method, we don't need to determine how many elements of the array there are.  Also, in the above example, if sDrives were a collection of objects that had members (properties and/or sub-classes) of their own, the sDrive variable could be used within the For-Each loop to expose and/or modify those members.

Testing the program so far

Save the project now.  Run the program.  Use it's down-arrow and take a look inside the cboDrives combobox.  Are all the drives on the computer listed:

Your drive letters list will vary.  When the user selects a drive from the list, we want the Size, Free Space, and Used Space information to be displayed.  We can use the SelectedIndexChanged event procedure of cboDrives to determine when the user has selected an item in the drive list. 

Begin by adding this line of code to the cboDrives_SelectedIndexChanged event procedure to construct an instance of a pDisk object:

Dim objDisk As New CompInfo.pDisk()

Recall that our Size, Free Space, and Used Space methods require the programmer to pass them the drive letter in this format: c:  That is, the drive letter followed by a colon (:), like this for example:

objDisk.Size("c:")

The entries in the cboDrives combobox include a backslash (\) as their last character, like this: c:\, (as shown in the above illustration).  We need to trim off the backslash (\) character from the end of the string when we pass the selected value from the cboDrives combo box to the methods of objDisk.  Fortunately this is really easy to do with the SubString method and Length property of cboDrives.Text, like this: 

Dim sDrive As String =  _
    
cboDrives.Text.SubString(0, cboDrives.Text.Length - 1)

The first parameter we pass to SubString (0) specifies the position in the string to start the extraction (0 is the first character), the second parameter (cboDrives.Text.Length - 1) is how many characters from the starting location to extract.  By starting at character position 0 and extracting to the Length of the string minus 1, we trim off the trailing backslash (\).  Add the above line of code to the cboDrives_SelectedIndexChanged event procedure.

Because the values returned by the Size, Free Space, and Used Space methods are strings that represent gigabyte values, we will need to use CDbl again to convert them into numbers that can be formatted with the Format function.  This time we will format the number to three decimal places, so that information about zip and floppy drives can be displayed.  Add this code to the bottom of the cboDrives_SelectedIndexChanged event procedure:

'Use the Size, FreeSpace, and UsedSpace methods
'    of pDisk class to determine info about sDrive.
lblSize.Text = _
    Format(
CDbl(objDisk.Size(sDrive)),  _
   
        "#,##0.000")  & " Gigabytes"
lblFreeSpace.Text =  _
    Format(
CDbl(objDisk.FreeSpace(sDrive)),  _
           
"#,##0.000")  & " Gigabytes"
lblUsedSpace.Text =  _
    Format(
CDbl(objDisk.UsedSpace(sDrive)),  _
           
"#,##0.000")  & " Gigabytes"
objDisk = Nothing

Testing the program so far

Save the project now.  Run the program.  Select a drive in the cboDrives combobox (if you pick drive A, make sure you have a floppy diskette inserted).  Does it work?

As a final detail, add an Exit button to the lower right corner of the form:

That completes Part A - Creating an OLE Client application for the CompInfo.dll Class Library

Part B

Converting a Class Library into a Component Library

Begin by closing the CompInfoTest project.  Select Close Project on the File menu.   Select Open Project on the File menu and navigate to your CompInfo project folder, open it, and double-click on the CompInfo.vbproj file to open last week's project.

Adding a Component to the CompInfo Class Library

The first step to converting the CompInfo Class Library into a Component Library is to add a Component file to the project.  Right-clicking on the CompInfo project in the solution explorer window and select Component... from the Add fly-out menu (as shown below):

On the Add New Item dialog, be sure to change the name from the default Component1.vb to Computer.vb, as shown below, and then click the Add button:

Take a look in your solution explorer window and you should now see a new Computer.vb component file as part of the project:

While a Class Library can contain many different objects (with each Class file containing one or more objects), none of those objects actually exist until you construct an instance of them, with a command like this:

Dim objCPU As New CompInfo.pCPU()

By adding a Component file to the CompInfo class library and constructing instances of all the classes within the Component file, we can have access to all of the objects that the class library contains without manually constructing them ourselves.  We do this by privately constructing all the objects within the Component file and adding Properties to the Component file that return a reference to each of the pre-constructed private objects.  This is called exposing objects.

Constructing the four Objects to be exposed through Computer.vb

Display the code view of the Computer.vb component file, and add the following code to the Declarations section:

Private objCPU As New pCPU()
Private
objDisk As New pDisk()
Private
objMem As New pMemory()
Private
objOS As New pOS()

These are the for objects (constructed from classes here) that we will expose through the component file Computer.vb.  It's important to declare these four object constructors as Private, so that programmers will not be able to access these objects directly through our Computer component.  We will make these instances of pCPU, pDisk, pMemory, and pOS available, but only by exposing them as the return values of four properties.

Adding four Object properties to Computer.vb

Insert a blank line above the End Class statement in the code view of the Computer.vb component file and add the following four properties:

'The CPU property exposes the private
'    instance of pCPU
ReadOnly Property CPU() As pCPU
   
Get
        Return
objCPU
    End Get
End Property

'The Disk property exposes the private
'    instance of pDisk
ReadOnly Property Disk() As pDisk
   
Get
        Return
objDisk
   
End Get
End Property

'The Memory property exposes the private
'    instance of pMemory
ReadOnly Property Memory() As pMemory
   
Get
        Return
objMem
   
End Get
End Property

'The OS property exposes the private
'    instance of pOS
ReadOnly Property OS() As pOS
   
Get
        Return
objOS
   
End Get
End Property

Save the project now. 

Rebuilding your Class Library into a Component Library

Right-click on the CompInfo project in the solution explorer window and select the Build menu item, as shown:

Once the compilation is complete (after just a few seconds), you should see this Build succeeded message in the lower left corner of the window:

Now your CompInfo.dll file has been transformed from a Class Library into a Component Library!

Using your new Component Library

Here we go again!  Close the CompInfo project.  Select Close Project on the File menu.  Select Open Project on the File menu and navigate to your CompInfoTest project folder, open it, and double-click on the CompInfoTest.vbproj file to open the CompInfoTest project.

The first thing we need to do after opening the CompInfoTest project is remove the reference to the old CompInfo Class Library.  Click on the Show All Files button at the top of the solution explorer window, then open the References folder.  Right-click on the CompInfo reference item (as show below). Select the Remove option to remove the old CompInfo reference from the project:

We will now add our Computer component to the Components section of the Control Toolbox.  Open the Control Toolbox and right-click anywhere in the Components section and select the Choose Items... option on the context menu, as shown:

When the Choose Toolbox Items dialog appears, be sure the .NET Framework Components tab is selected.  This is a list of all of the .NET Components that are included with Visual Studio 2010.  Click on the Browse button (as show below) so that we can add our CompInfo.dll component library to the list:

Click on the My Projects icon on the left side of the Open dialog, as shown below:

Then navigate to the CompInfo\bin\Release folder, select the newly created CompInfo.dll file and click the Open button.

You should now see a new Computer entry in the .NET Framework Components list, as shown below:

Notice that the Namespace column says CompInfo.  That is because the Namespace value for project 7 was not modified when we added a component file to the project.  In fact, we could have added multiple components to the project and the Namespace would remain unchanged.  But the name of the Computer component is listed in the Name column.  The Name column lists only the Components in the CompInfo.dll file.  With the new Computer item check marked, click the OK button to add your Computer component to the Components section in the Control Toolbox, as shown below:

To add a Computer component to your project, double-click on the new Computer item in the Control Toolbox now.  You should then see a new Computer1 item in the Component Tray at the bottom of the designer window, like this:

Modifying the code to use the new Computer Component

Go to code view window of frmCompInfoTest, and delete these three object constructor statements from the frmCompInfoTest_Load event procedure:

Dim objCPU As New CompInfo.pCPU()
Dim objMem As New CompInfo.pMemory()
Dim objOS As New CompInfo.pOS()

Recall that we added private constructors for these objects to the Declaration section of the Computer component.  So we don't need to create them again here.  Let's take a look at the first line of code that displayed the number of CPU's in the computer by using the Count property of the pCPU object:

'Display the CPU Information
lblCount.Text = objCPU.Count

Modify this line of code to use the new Computer1 component, like this:

'Display the CPU Information
lblCount.Text = Computer1.

Notice that Computer1 has a CPU property, as shown: 

Important: Recall that the CPU property of our Computer component returns a reference to the privately created pCPU object that we constructed in the Declarations section of the component file. 

Select CPU from the pop-down list and type a dot (.) to see this:

All the properties of the pCPU object are listed!  Select Count so that the finished line of code looks like this:

'Display the CPU Information
lblCount.Text = Computer1.CPU.Count

Continue modifying the other lines of code in the frmCompInfoTest_Load event procedure to use the Computer1 component.  For example, change:

lblArchitecture.Text = objCPU.Architecture
lblLevel.
Text = objCPU.Level
lblVersion.
Text = objCPU.Version
lblIdentifier.
Text = objCPU.Identifier

To:

lblArchitecture.Text = Computer1.CPU.Architecture
lblLevel.
Text = Computer1.CPU.Level
lblVersion.
Text = Computer1.CPU.Version
lblIdentifier.
Text = Computer1.CPU.Identifier

Continue modifying the remaining code in the  frmCompInfoTest_Load event procedure to use the Computer1 component.   Don't forget to delete these three lines:

objCPU = Nothing
objMem
= Nothing
objOS
= Nothing

Important: Don't forget to also modify the code in the cboDrives_SelectedIndexChanged event procedure to use the Computer1 component.

Recall that before we added our custom Computer component to this project we removed the reference to the old CompInfo Class Library from the References folder in the solution explorer window.  Take a look inside the References folder now (as shown below).  Notice that the reference to CompInfo is back!  This was set automatically by the addition of the Computer component to the project.  When a Component uses classes from a Class Library, as the Computer component does, these references are inherited by the project that uses that component automatically.  As a side note, this means that we can still construct the objects within CompInfo.dll ourselves if we wish.  We have the option to use CompInfo.dll as a class library or a component library:

Testing the program

Save the project and run it.  Does it work?

A Class Library verses a Component

We've done this program both ways.  First as a Class Library, where we had to construct the objects as we needed them.  Second with a Component Library, where the objects are pre-constructed and exposed through the Computer component that we added to the Class Library.

While a Class Library doesn't need to contain components, where ever you find a Component you will also find a Class Library.  Microsoft doesn't really distinguish between the two.  As our CompInfo.dll file is right now, nothing is stopping a programmer from setting a reference it and constructing the pCPU, pDisk, pMemory, and pOS objects manually—as we did in part A of this project.  Or they can add the CompInfo.dll file to the control toolbox as the Computer component.  Then when they insert a Computer component into their project they can access the pCPU, pDisk, pMemory, and pOS objects that are pre-constructed and exposed through it.


To copy a Project folder from your Projects folder on the Hard Drive to a floppy diskette or pen-drive follow these steps:

  1. Exit Visual Studio 2010 and insert the floppy diskette or pen-drive, that you want to copy the CompInfoTest folder to:
  2. Select the My Documents item on the Start Menu to open the My Documents folder.
  3. In the My Documents folder, double-click the Visual Studio 2010 folder to open it.
  4. Double-click on your Projects folder to open it.
  5. Open the CompInfoTest folder by double-clicking on it.  Inside the CompInfoTest folder, delete the Obj and Bin folders.  Important: Be sure not to delete the My Project folder or Resources folder.
  6. Once you have deleted the Obj and Bin folders, hit the Backspace key once—or click the Back button on the toolbar.  This moves you from inside the CompInfoTest folder to back inside your Projects folder.
  7. Right-click on the CompInfoTest folder and selected: 31/2" Floppy A: or your pen-drive on the Send To fly-out menu.  This copies the CompInfoTest folder to your floppy diskette or pen-drive.