Building the Visual Basic Component

We will now see how to build the VB component, which will be called from our ASP page. This component will return an HTML page containing a table with the products in the selected category.

Create a new Visual Basic ActiveX DLL project called prjRetrieveWebInfo. Add references to the Microsoft Active Server Pages Object Library and to the prjWebProduct we just created. Make a reference to the MTS library. We will make this an MTS component, though there may not be too much gained by doing this. However, since we are using the Response object and Request object from the ASP page, and the ASP page is running under MTS, we will choose to run this component under MTS. My computer is using Windows 2000 Beta, so the MTS library is now replaced by COM+ Services Type Library.

References - pr jRetrieveWeblnfo.ybp

Available References:

0 Visual Basic For Applications 0 Visual Basic runtime objects and procedures 0 Visual Basic objects and procedures 0 OLE Automation 0 COM4- Services Type Library 0 Microsoft Active Server Pages Object Library

D IAS Helper COM Component 1.0 Type Library

□ IAS RADIUS Protocol 1.0 Type Library

□ Active DS IIS Extension Dll

□ Active D5 IIS Namespace Provider

□ Active DS Type Library D Active Server Pages ObjectContext Object Library I-! Active Setup Control Librarv

Priority

Help

prjWebProduct

Location: C:\Wrox\VB6 UML\Products\prjWebProduct.d Language: Standard

Change the class name to clsWeb. Add the following code to the class: Option Explicit

Private m_objContext As ObjectContext Implements ObjectControl

We have implemented the ObjectControl interface so that our control can run under MTS. This means we must implement all of the methods of the ObjectControl, so we need to add the following code to the ObjectControl methods. When our object is instantiated, the ObjectControl_Activate event will be fired. We can use this event to get a reference to the ObjectContext object:

Private Sub ObjectControl_Activate()

Set m_objContext = GetObjectContext End Sub

When the object is destroyed, the ObjectControl_Deactivate event will be raised, and we must destroy the ObjectContext object:

Private Sub ObjectControl_Deactivate()

Set m_objContext = Nothing End Sub

Finally, we will also have to implement the ObjectControl_CanBePooled function, although this does not actually have any functionality at present. However, we may get an error if we don't implement the entire ObjectControl interface:

Private Function ObjectControl_CanBePooled() As Boolean

ObjectControl_CanBePooled = False End Function

We will use a custom function called CreateInstance to create our components. If the current component is running under MTS, the CreateInstance function will use the MTS Ob jectContext object's CreateInstance function. Otherwise, we will use the New keyword:

Private Function CreateInstance(ProgID As String) As Object On Error GoTo CreateInstanceError

If Not m_objContext Is Nothing Then

Set CreateInstance = m_objContext.CreateInstance(ProgID) Else

Select Case ProgID

Case "prjWebProducts.clsProducts"

Set CreateInstance = New prjWebProduct.clsProducts End Select End If

Exit Function CreateInstanceError:

Err.Raise Err.Number, Err.Source & " CreateInstance", Err.Description End Function

We will also create sub routines for SetComplete and SetAbort to commit or abort the transaction if MTS is running:

Public Sub SetComplete()

If Not m_objContext Is Nothing Then m_objContext.SetComplete End If End Sub

Public Sub SetAbort()

If Not m_objContext Is Nothing Then m_objContext.SetAbort End If End Sub

We will create a function called BuildProductsByCategoryTable. This function takes the CategoryID as a parameter and will return a string with HTML tags to place the product information into a table,

Public Function BuildProductsByCategoryTable _

(ByVal v_vCategoryID As Variant) As Variant Dim lngCategoryCounter As Long Dim strHTML As String Dim strQuery As String

Dim objProduct As prjWebProduct.clsProducts Dim lngProductCounter As Long

This function will use the Products object to retrieve the data, so we will create the Products component:

Set objProduct = CreateInstance("prjWebProducts.clsProducts")

We can use the GetProductCollection method of this object to build a collection of products with the ProductID that was passed into the function:

objProduct.GetProductCollection(e_ProductsCategoryID)

We will now build an HTML page to place this information into a table using the properties of the product object. We will begin by building the header of the page:

strHTML = "<HTML>" & vbCrLf & _ "<HEAD>" & vbCrLf & _

"<TITLE>" & "Products by Category" & "</TITLE>" & vbCrLf & vbCrLf & _ "</HEAD>" & vbCrLf & vbCrLf & _ "</HEAD>" & vbCrLf & vbCrLf & _

"<BODY TEXT=" & Chr(34) & "#000000" & Chr(34) & _

" BGCOLOR=" & Chr(34) & "#FFFFFF" & Chr(34) & " LINK=" & Chr(34) & _ "#0000FF" & Chr(34) & " VLINK=" & Chr(34) & "#6600CC" & Chr(34) & _ " ALINK=" & Chr(34) & "#FF0000" & Chr(34) & " TOPMARGIN=" & Chr(34) & _ "0" & Chr(34) & " LEFTMARGIN=" & Chr(34) & "0" & Chr(34) & ">" & _ vbCrLf & vbCrLf & vbCrLf & "<BR>" & vbCrLf

We have hard coded the category options into the page as there are only a few of them and we did not build a Category object in the VB6 UML book (though you can generate one with the code generator in a few seconds). If there were only a few categories then it might save time to create an array of the product names upon initialization to eliminate the need to look up the products every time. This array could then be looped through in the code to get the category names. If a new category were added, only the code for initializing the array would have to be changed. If the categories changed frequently, we would have to get the names dynamically.

Select Case v_

vCategoryID

Case O

strHTML

= strHTML

&

"<B>

Beverages Category </B>" & "<BR>" & vbCrLf

Case 1

strHTML

= strHTML

&

"<B>

Condiments Category </B>" & "<BR>" & vbCrLf

Case 2

strHTML

= strHTML

s

"<B>

Confections Category </B>" & "<BR>" & vbCrLf

Case 3

strHTML

= strHTML

s

"<B>

Dairy Products Category </B>" & "<BR>" & vbCrLf

Case 4

strHTML

= strHTML

s

"<B>

Grains/Cereals Category </B>" & "<BR>" & vbCrLf

Case 5

strHTML

= strHTML

s

"<B>

Meat/Poultry Category </B>" & "<BR>" & vbCrLf

Case 6

strHTML

= strHTML

s

"<B>

Produce Category </B>" & "<BR>" & vbCrLf

Case 7

strHTML

= strHTML

s

"<B>

Seafood Category </B>" & "<BR>" & vbCrLf

End Select

Now we will build the HTML table to put the product information in:

strHTML = strHTML & "<TABLE BORDER=1 CELLSPACING=1 CELLPADDING=1 WIDTH=" & Chr(34) & Str(25) & Chr(34) & ">" & vbCrLf & _ "<CAPTION>" & "Products By Category" & "</CAPTION>" & vbCrLf

Next, we put in the headers for the table:

strHTML =

strHTML s vbCrLf

s '

'<TH>" s _

"Product Name" s

"</TH>"

strHTML =

strHTML s vbCrLf

s '

'<TH>" s _

"Product Quantity Per Unit" & _

"</TH>"

strHTML =

strHTML s vbCrLf

s '

'<TH>" s _

"Unit Price" s _

"</TH>"

strHTML =

strHTML s vbCrLf

s '

'<TH>" s _

"Units In Stock"

s _

"</TH>"

strHTML =

strHTML s "</TR>"

s

vbCrLf

Then we set the CategorylD of the Product object and refresh the object:

objProduct.CategorylDEquals = v_vCategoryID + 1 objProduct.GetProductCollection(e_ProductsCategoryID).Refresh

We can then use the object to retrieve the information we need:

With objProduct.GetProductCollection(e_ProductsCategoryID).Item objProduct.GetProductCollection(e_ProductsCategoryID).MoveFirst For lngProductCounter = 1 To _

objProduct.GetProductCollection(e_ProductsCategoryID).RecordCount

Now we add the products into the table:

strHTML =

strHTML

&

"<TR>"

strHTML =

strHTML

&

"<TD align =" & Chr(34) &

"center"

&

Chr(34)

&

strHTML =

strHTML

&

.ProductName & "</TD>"

strHTML =

strHTML

&

"<TD align =" & Chr(34) &

"center"

&

Chr(34)

&

strHTML =

strHTML

&

.QuantityPerUnit & "</TD>"

strHTML =

strHTML

&

"<TD align =" & Chr(34) &

"center"

&

Chr(34)

&

strHTML =

strHTML

&

"$" & .UnitPrice & "</TD>"

strHTML =

strHTML

&

"<TD align =" & Chr(34) &

"center"

&

Chr(34)

&

strHTML =

strHTML

&

.UnitsInStock & "</TD>"

strHTML =

strHTML

&

"<TD align =" & Chr(34) &

"center"

&

Chr(34)

&

Move to the next record and loop:

objProduct.GetProductCollection(e_ProductsCategoryID).MoveNext strHTML = strHTML & "</TR>" & vbCrLf Next End With

End the table and return the HTML string:

strHTML = strHTML & " </TABLE> " & vbCrLf & "<BR>" BuildProductsByCategoryTable = strHTML End Function

We will use the BuildProductsByCategoryTable function in other functions. For example, we could return all of the products in a function called GetGeneralProductInformation. This will be called from the ASP page. We will use an ASP Response object as a parameter for this function. This function will loop through all of the products. To keep it simple, I am hardcoding the number of products, but in production code we would use a long constant for the number of categories. We will use the Write method of the Response object in our Visual Basic web component to return the string:

Public Sub GetGeneralProductInformation(ByVal v_vUserID As Variant, _

ByVal v_vPassword As Variant, ByVal v_oResponse As ASPTypeLibrary.Response) Dim lngCategoryCounter as Long For lngCategoryCounter = 0 to 7

v_oResponse.Write BuildProductTable() Next End Sub

We can also build another function that reads from the HTML page we initially created, with the combo box with categories. In this case, we will need the ASP Request object so we can know which category they selected. The code would look as follows:

Public Sub GetCategoryInformation(ByVal v_vUserID As Variant, _

ByVal v_vPassword As Variant, _

ByVal v_oResponse As ASPTypeLibrary.Response, _ ByVal v_oRequest As ASPTypeLibrary.Request)

v_oResponse.Write BuildProductsByCategoryTable(v_oRequest.QueryString("select1"))

End Sub

We can create an entire range of pages using Visual Basic. For example, we could create an error page as follows:

Private Function BuildLoginErrorPage(ByVal v_sErrorDetails As String) As

Variant

Dim strHTML As String

strHTML = "<HTML>" & vbCrLf & _

"<HEAD>" & vbCrLf & vbCrLf & _

" <TITLE>Introduction Page</TITLE>" & vbCrLf & vbCrLf & _

"</HEAD>" & vbCrLf & _

"<BODY TEXT=" & Chr(34) & "#000000" & Chr(34) & " BGCOLOR=" & Chr(34)

& _

"#FFFFFF" & Chr(34) & "LINK=" & Chr(34) & "#0000FF" & Chr(34) & _

" VLINK=" & Chr(34) & "#6600CC" & Chr(34) & " ALINK=" & Chr(34) & _

"#FF0000" & Chr(34) & " TOPMARGIN=" & Chr(34) & "0" & Chr(34) & _

" LEFTMARGIN=" & Chr(34) & "0" & Chr(34) & ">" & vbCrLf & vbCrLf & vbCrLf & _

"<!------MAIN INFO---->" & vbCrLf & vbCrLf & _

"<BR><BR>" & vbCrLf & vbCrLf & _

"<CENTER>" & vbCrLf & _

"<FONT FACE=Helvetica, Arial SIZE=+3>" & vbCrLf & _

"Please try again...login Failed" & vbCrLf & _

"</FONT>" & vbCrLf & _

"</CENTER>" & vbCrLf & vbCrLf & _

"<BR>" & vbCrLf & _

"<BR>" & vbCrLf & _

"<BR>" & vbCrLf & vbCrLf & _

"<CENTER>" & vbCrLf & _

"<FONT FACE=" & Chr(34) & "Arial, Helvetica" & Chr(34) & " FONT SIZE=

' & _

Chr(34) & "2" & Chr(34) & ">" & Chr(34) & vbCrLf & vbCrLf & _

v_sErrorDetails & vbCrLf & vbCrLf & _

"</center>" & vbCrLf & _

"</FONT>" & vbCrLf & _

"<FONT FACE=" & Chr(34) & "Arial, Helvetica" & Chr(34) & " FONT SIZE=

' & _

Chr(34) & "1" & Chr(34) & ">" & Chr(34) & vbCrLf & vbCrLf & _

"All contents ©1999, Northwind, All Rights Reserved." & vbCrLf & _

"</center>" & vbCrLf & _

"</FONT>" & "</BODY>" & vbCrLf & "</HTML>" _

BuildLoginErrorPage = strHTML

End Function

There are many different options when it comes to building HTML pages. You could also store the HTML as text in a database and create a component to retrieve and save the HTML pages. There would, however, be extra overhead to connect to the database to get the HTML text. It is only through testing that you could tell if this was a workable solution for your system. If the HTML pages were in the database, hackers could not alter them. You would, though, have to create a staging area where your developers would first place the pages for initial testing. Once the text was correct, they could be moved into the database.

The process of moving pages could be automated. The only pages that could be accessed by a hacker would be the ASP pages that call your Visual Basic components. Even these could be protected by placing the ASP pages in a database and pushing the correct ASP pages out onto the web server periodically. If you needed to make a change to the ASP pages, you would place the new ASP page into the database and when the next push came the new version would go out onto the web server. In this way, no one would have permission to change the ASP pages directly. If someone did find a way to hack into the system and change the ASP pages, the hacked pages would automatically be replaced during the next refresh of the pages. Unfortunately, we must take these things into consideration.

While ASP pages can be replaced without shutting the server down, the same is not true of Visual Basic web classes. Because web classes are DLLs, they will require the web server to be stopped before you can replace them. This is a serious limitation and one of the reasons why ASP is still a better option than web classes.

Let us now turn to a different example where our products component can be used.

Using DHTML

Dynamic HTML is a great tool for the intranet. Unfortunately, Netscape Navigator 4.0 and Microsoft Internet Explorer 4.0/5.0 differ considerably in their implementations of DHTML, so DHTML solutions are not useful on the Internet (unless you do not mind creating solutions only for people with current releases of one or the other major browser). On an intranet, you can control what browsers are on the client machines and make sure that everyone has a DHTML-compliant machine.

In this example, we will again use the original Products component. We will create the same HTML page with a combo box on it. In addition to the HTML code for the combo box, we will now also have VBScript code in our HTML page. This VBScript code will use the Products component to retrieve the products for the category selected and insert a table with those products into the HTML page. This means that we will get the product information directly and rebuild the page without ever going to the web server. This eliminates delay times and makes the web application run just like a Visual Basic EXE application.

Coding the DHTML HTML Page

You can create this page in Microsoft Visual Interdev or any text editor (such as the perennial favorite, Notepad). We will begin by putting the tag in that says we are about to write Visual Basic Script:

<SCRIPT LANGUAGE=VBSCRIPT>

We will later place a list box onto the page. We will call that list box lstCategory. When that list box has been clicked, we will want to place a table with the current products into our HTML page without calling the web server. We will place our code into the OnPropertyChange event of the lstCategory list box. Add this to your HTML page:

Sub lstCategory_OnPropertyChange

Dim strHTML

Dim strQuery

Dim lngProductCounter

Dim e_ProductsCategoryID

e_ProductsCategoryID=1

Notice that in VBScript all variables are late-binding variants. With DHTML, you do not create your components with the New keyword. You will create the object in the HTML section of your code. The HTML code later in the page will create an object called obj Product, which is a reference to the product object. We will first initialize the product collection:

objProduct.GetProductCollection(e_ProductsCategoryID)

We want to place the name of the category selected above our product table. We can access the value of the item selected in the listbox using the expression lstCategory. value.

Select Case lstCategory.

.value

Case 0

strHTML =

strHTML

&

"<B>

Beverages Category </B>" & "<BR>" & vbCrLf

Case 1

strHTML =

strHTML

&

"<B>

Condiments Category </B>" & "<BR>" & vbCrLf

Case 2

strHTML =

strHTML

&

"<B>

Confections Category </B>" & "<BR>" & vbCrLf

Case 3

strHTML =

strHTML

&

"<B>

Dairy Products Category </B>" & "<BR>" & vbCrLf

Case 4

strHTML =

strHTML

&

"<B>

Grains/Cereals Category </B>" & "<BR>" & vbCrLf

Case 5

strHTML =

strHTML

&

"<B>

Meat/Poultry Category </B>" & "<BR>" & vbCrLf

Case 6

strHTML =

strHTML

&

"<B>

Produce Category </B>" & "<BR>" & vbCrLf

Case 7

strHTML =

strHTML

&

"<B>

Seafood Category </B>" & "<BR>" & vbCrLf

End Select

We now initialize our table:

strHTML = strHTML & "<TABLE BORDER=1 CELLSPACING=1 CELLPADDING=1" & _ "WIDTH=" & Chr(34) & "25" & Chr(34) & ">" & vbCrLf & _ "<CAPTION>" & "Products By Category" & "</CAPTION>" & vbCrLf strHTML = strHTML & vbCrLf & "<TH>" & _ "Product Name" & _ "</TH>"

strHTML = strHTML & vbCrLf & "<TH>" & _

"Product Quantity Per Unit" & _ "</TH>"

strHTML = strHTML & vbCrLf & "<TH>" & _ "Unit Price" & _ "</TH>"

strHTML = strHTML & vbCrLf & "<TH>" & _ "Units In Stock" & _ "</TH>"

strHTML = strHTML & "</TR>" & vbCrLf

We need to set the CategoryIDEquals property of the Products component. The CategoryID field is one-based, but lstCategory.value is zero-based, so we will have to add one first:

objProduct.CategoryIDEquals = lstCategory.value + 1

Next, we refresh the Products component and move through the items. You will notice this is the same code we used in the Visual Basic web component:

objProduct.GetProductCollection(e_ProductsCategoryID).Refresh With objProduct.GetProductCollection(e_ProductsCategoryID).Item objProduct.GetProductCollection(e_ProductsCategoryID).MoveFirst For lngProductCounter = 1 To _

objProduct.GetProductCollection(e_ProductsCategoryID).RecordCount

strHTML =

strHTML

&

"<TR>"

strHTML =

strHTML

&

"<TD align =" & Chr(34) &

"center"

&

Chr(34)

&

">

strHTML =

strHTML

&

.ProductName & "</TD>"

strHTML =

strHTML

&

"<TD align =" & Chr(34) &

"center"

&

Chr(34)

&

">

strHTML =

strHTML

&

.QuantityPerUnit & "</TD>"

strHTML =

strHTML

&

"<TD align =" & Chr(34) &

"center"

&

Chr(34)

&

">

strHTML =

strHTML

&

"$" & .UnitPrice & "</TD>"

strHTML =

strHTML

&

"<TD align =" & Chr(34) &

"center"

&

Chr(34)

&

">

strHTML =

strHTML

&

.UnitsInStock & "</TD>"

strHTML =

strHTML

&

"<TD align =" & Chr(34) &

"center"

&

Chr(34)

&

">

objProduct.GetProductCollection(e_ProductsCategoryID).MoveNext strHTML = strHTML & "</TR>" & vbCrLf Next End With strHTML = strHTML & " </TABLE> " & vbCrLf & "<BR>"

We will use something that is called a <DIV> element. A <DIV> element is one of the most important parts of a DHTML application. We can place a <DIV> element into our HTML code, and then we can insert text between the element's opening and closing tags. We can also replace text between the <DIV> tags. This allows you to add, remove or change sections of your HTML page using script code. In this case, we are inserting strHTML, which contains our table in HTML format, into our <DIV> element, which we will call "proddiv". The innerhtml property contains everything between the opening <DIV> tag and the closing </DIV> tag, including any other HTML tags. Thus, using the innerhtml property, we can insert text between the two tags.

document.all.tags("div").Item("proddiv").innerhtml=strHTML End Sub

Finally, we have the closing </SCRIPT> tag, and we begin the regular HTML part of our HTML page:

<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">

To get a reference to our object, we will use an <OBJECT> element in our HTML page. The object tag has a classid attribute, which must be set to the GUID of a public creatable class. Notice that there is the word clsid included with the GUID. The id attribute gives the object a name that can be referenced in code. CODEBASE gives us the location of the object if it is not on the client machine. You should create a package called a Cab file to distribute your files through the Inter/Intranet. The Visual Basic Package and Deployment wizard can make your Cab files for you (see Chapter 11). In this case, I have created a Cab file called prjProducts. cab that is located in the same directory as this HTML file. The string "1,0,0,0" is the version number. If there is a copy of prj Products on the client and the version number is higher or equal to this number, the file will not be downloaded. If there is no copy of prj Products on the computer or a copy with a lower version number, the file will be downloaded. We have also set CategoryIDEquals to a default of 1.

<object classid="clsid:C4 9C5681-37CC-11D3-A807-009027887C34" id="objProduct" CODEBASE="prjProducts.cab#Version=1,0,0,0"> <param NAME="CategoryIDEquals" = "1"> </object>

Next, we build the listbox:

<P><STRONG>Select

A Category</STRONG>

<P></P>

<P>

<P>

<SELECT id=LstCategory name=lstCategory style="HEIGHT: 22px; WIDTH: 150px">

<OPTION Value="0"

selected>Beverages Category</OPTION>

<OPTION Value="1"

>Condiments Category</OPTION>

<OPTION Value="2"

>Confections Category</OPTION>

<OPTION Value="3"

>Dairy Products Category</OPTION>

<OPTION Value="4"

>Grains/Cereals Category</OPTION>

<OPTION Value="5"

>Meat/Poultry Category</OPTION>

<OPTION Value="6"

>Produce Category</OPTION>

<OPTION Value="7"

>Seafood Category</OPTION>

</SELECT></P>

<P><INPUT id=ChooseCatagory name=ChooseCatagory Onclick=ChooseCategory type=Button

value=Submit></P>

<P></P>

<INPUT id=text1 name=text1>

We will now put our <DIV> tag in. We are placing it below the listbox so we can insert the data directly below the list box.

<div ID="proddiv">

There are many possibilities with DHTML. For example, you could bring over information in the form of XML and use that data to create a dynamic application on the client that does not need to communicate to a server. We have only had a glimpse of its potential for use with Visual Basic components.

365 Days Of Motivation

365 Days Of Motivation

Stop Wasting Time And Learn How To Stay Motivated. Finally! Discover How To Stop Your Mind From Wandering, And Upgrade Your Motivation. You Can Hack Your Motivation Levels, Allowing You To Take Your Life To The Next Level.

Get My Free Ebook


Post a comment