Channels ▼


Reinventing the Web

Source Code Accompanies This Article. Download It Now.

Dr. Dobb's Sourcebook May/June 1997: 20/20

Al is the author of Developing ActiveX Web Controls and the forthcoming Developing ActiveX Controls with Visual Basic 5 (both from the Coriolis Group). You can reach Al on the Web at com/awc/.

I invented the World Wide Web. Well, not really. But I might have, and a lot of other people might have, too. It's just that we didn't. Tim Berners-Lee did. Let me explain. Years ago (when DOS was king), my company created two products in response to demands from our clients. One was E-book, a hypertext document system. It allowed text formatting and hyperlinks between documents. Another product we sold in those days was FORMZ, a form processor. You could define fields and choices and submit the form to a script for processing. Gee, kind of sounds like a web browser doesn't it?

There were at least two things that prevented Al Williams Inc. from taking the world by storm: First, I didn't merge the products into one. Besides that, I never saw the utility of making E-book and FORMZ network aware to the point that the documents and scripts could reside on a remote host. Stupid me. Of course, many other companies had similar products. Microsoft had WinHelp that it tried to convert into a multimedia authoring language -- again, not really network aware. There are countless others.

If you think about it, what was revolutionary about Tim Berners-Lee's invention? The technology? No, many people had been writing hypertext and similar programs for a long time. A breakthrough in data representation? No, HTML is really a form of SGML. Tim Berners-Lee's web revolution was because of an idea. An idea to juxtapose two well-understood technologies: hypertext and networking. Amazing.

Many great ideas are just that simple: putting things together in a way no one has ever thought of before. Look at the Weed Eater. If it had a blade on it, anyone could have thought of it (and many people did). No one would think of fishing line as a high-tech innovation. Someone put them together and changed the way you cut your lawn.

Isaac Newton once said, "If I have seen further, it is by standing upon the shoulders of Giants." Sir Isaac would appreciate component software. Imagine if my E-book and FORMZ programs had been components. Maybe I'd have put them together. Perhaps I'd have added a networking component, too. Even better, maybe one of my clients would have made the connection that I failed to make.

This month I'll show you how you can reuse existing ActiveX components to make entirely new ActiveX components with Visual Basic 5. Since I've been talking about web browsers, I'll make one that you can drag and drop into any ActiveX container. Of course, I don't want to write all the code to parse HTML, encode form data, and render pictures. Instead, I'll stand on Microsoft's shoulders and use the Internet Explorer (IE) web browser control.

Why a New Control?

If IE provides a browser control, why should you write another one? Primarily because the IE control doesn't provide a user interface. Sometimes this is what you want -- just a blank window full of HTML. Many times, however, you'd like to have a complete browser with controls and the other accouterments you expect on a browser. Besides, perhaps you'll merge the browser with some other innocuous component and get rich and famous!

Of course, VB5 already has a browser form, but you can only include that as part of another VB program. With a true control, you can use it in any ActiveX container.

If you read the ActiveX SDK documentation, you might think Microsoft has a way for you to use a full-featured browser already. That's not really true. The SDK talks about the two browser objects: InternetExplorer and WebBrowser. The InternetExplorer object has a full interface. It is also a complete running instance of IE. InternetExplorer isn't a control; it is an OLE automation interface that you can use to control a copy of IE.

The WebBrowser control is a proper component, but it lacks any user interface. If you want to see the difference, open up VB5 and start a standard EXE project. From the Project menu, select Components. Then on the Controls tab, select Microsoft Internet Controls, and press OK. Notice the new icon on the tool palette? That is the WebBrowser control. For now, open the Form_Load event handler, add Example 1(a), and run the program. Not exactly the results you'd like, right? Now try dragging a WebBrowser control on your main form. Then replace the Form_ Load event code with Example 1(b).

That's better (assuming you have a connection to the Internet active; otherwise, you might want to specify a local URL). The only problem is that there are no controls to operate the browser. Sure, you can drag buttons on to the form and use them to trigger methods in the WebBrowser control. However, I want a true component that has all the necessary controls ready to go.

Getting Started

The first step to creating a new control that encapsulates the WebBrowser control is to plan it! Figure 1 shows the general appearance I wanted for the control. Notice the graphical buttons -- the component should encapsulate these and not use external files that the final developer will have to carry around.

For this control, I decided to expose several members of the WebBrowser and UserControl objects (see Table 1). The only unique member is ShowStatus, a flag that determines if the browser shows its status bar or not.

Armed with a plan, it is trivial to start a new ActiveX Control project. This causes VB to create a blank UserControl object which is similar to a form, but is really an ActiveX control. You drag buttons, static text, and text boxes on to the UserControl just as you would any ordinary VB form. To get the WebBrowser control to appear you'll have to add it using Tools/Components again (since this is a new project). The WebBrowser control may not draw correctly at design time, but don't worry about it.

The browser needs to recalculate the layout of all the internal controls when the main control resizes. Therefore, you don't need to worry about the design-time layout (see Figure 2). After all the code is in place, the internal components will move to the correct places when the main control starts (and every time it resizes, too).

Defining Members

Defining members in VB5 is simple. Just use the ActiveX Interface Wizard to specify the members and connect them to the underlying components (see Figures 3, 4, and 5). In the case of the ShowStatus property, you'll need to manually define it, even though it corresponds closely to the URL.Visible property. You can do that on the final screen of the Wizard (see Figure 6).

You would think that selecting default property names in the Wizard would cause the Wizard to assign the correct dispatch IDs for these properties. However, it doesn't. You'll need to go to the Procedure Attributes menu item (on the Tools menu), press the Advanced button, and change the Procedure ID field to match the names of the standard properties (see Figure 7). While you are at it, you can set the property categories, if you like.

Another annoyance is that the Wizard doesn't define certain members to be the correct type. Look at the properties for a form. Notice the BorderStyle property, in particular. It has six possible values (0-5). However, the property editor shows the values with descriptive tags (like Sizable, for example). It does this because VB defines an Enum for a special type used only with BorderStyle. However, the Wizard defines our BorderStyle property as an Integer. Therefore, the property editor doesn't show the descriptive tags for our BorderStyle.

I decided not to worry too much about this, since I think the Wizard will work properly when VB5 is released. However, if you can find the name of the enumeration, just patch up the code to treat the property as the correct type. Most (but not all) of the types are visible in the object browser (look in the View menu). If you prefer, you can define your own enumeration. Look at the ShowStatus property in Listing One to see how that works. Example 2 is the Enum for that property.

Since the ShowStatus property uses the BrStatusType, the property browser works as you'd expect. For those that don't work right, the end programmer simply has to look up the numeric value in Help and plug it in directly. Remember, this is a beta copy of VB5, and I strongly suspect the release version won't have this problem.

Making it Work

Making the control work is perhaps the easiest part of the whole process. The buttons all correspond to simple methods in the WebBrowser control (see Table 2 and Listing One). The only odd things to implement are the URL entry bar near the top, the logo that changes color to indicate progress, and the status bar. I'll show you how the logo works after we talk about resources. The other interface elements are trivial.

The URL bar examines keystrokes using the Url_KeyPress event handler. If the key is equal to 13 (the Enter key), the code calls the WebBrowser.Navigate method, passing the contents of the URL bar. It also sets the key to 0 so that the control doesn't generate a beep to indicate that it doesn't know what to do with the key.

The status bar requires a bit more work. The WebBrowser control generates StatusTextChange events when it has updated status text. Sometimes this text is empty, so the event handler in the component ignores empty text. This always keeps the last message in the status bar, which is often useful. Otherwise, the code just copies the text passed with the event into the status bar's caption.

Using Resources

How can you handle the pictures used for the buttons and the progress logo? It would be a bad idea to require the component's users to have bitmap files. Instead, you want to build the bitmaps into the control. You can do this with resources.

Resources are nothing more than binary data attached to a program file (in this case, an ActiveX control in a DLL). Resources can be icons, bitmaps, dialog boxes, strings, or even user-defined data. In this case, you want to store bitmaps.

The first step to adding a resource is to build an RC file using a text editor. The RC file in this case is quite simple (see Listing Two). Each line defines a relationship between a number and an ordinary bitmap file. You'll use the number in your program to retrieve the picture as a Picture object.

Once you have the RC file completed, you have to run RC (a Microsoft program) to create a RES file. Just name the RC file on RC's command line; RC PICS.RC, for example, creates PICS.RES. The RES file contains a binary representation of the RC file and all of the data in each BMP file, as well. You add the RES file to your control project using Add File on the Project menu. Now your project contains the bitmaps (and any other resources mentioned in the RC file).

How do you access the pictures? Simply use LoadResPicture. You'll need to pass it the number of the image and vbResBitmap to indicate that you want a bitmap. The vbResBitmap constant is necessary because it is possible to have an icon, for example, that uses the same number as a bitmap. This call returns a Picture object that you can use just like any other picture object. Listing One loads all the pictures into the buttons (and the logo control) during the UserControl_Initialize event.

There are many other kinds of resources you can add to an RC file (see Table 3). There are also many editors designed to permit you to create and edit RC files graphically. Practically every Windows C++ environment comes with such a tool. Resource editors also are available as separate products.

Of course, you only use LoadResPicture for icons, bitmaps, and cursor images (vbResIcon, vbResBitmap, and vbResCursor, respectively). Use LoadResString to read strings from your resources. You can also use LoadResData to load nearly anything from your resources to a byte array (see Table 4). Of course, in most cases, it isn't very useful to load a bitmap as a byte array.

Notice that the code also resizes the buttons to match the size of the picture. Doing this requires a little understanding about the Width and Height parameters that different components support under VB. By default, forms and user controls always specify units in TWIPS (1/20 of a point or 1/1440 of an inch). Buttons and similar controls use whatever value their container uses. Pictures, however, are different. The Picture object's measurements are always in HIMETRIC units (Windows slang for 1/100 of a millimeter). Although you could convert HIMETRIC to TWIPS, it is easier to change the user control to use millimeters. You can do this by changing the ScaleMode property on the user control itself. Then it is a simple matter to divide the Picture's HIMETRIC values by 100 to obtain millimeter measurements (remember, Height and Width don't have to be integers).

You can find the conversion code in the SetButton subroutine. This simple function reads the bitmap from the resources, and sets the button size to match (after scaling millimeters to HIMETRIC units).

Another use for LoadResPicture is in creating the color-changing logo. When the WebBrowser control fires a ProgressChange event, the component loads a different color bitmap from the resources into the Logo control. When the DownloadComplete event occurs, it resets the logo back to its original state. The code also uses DownloadComplete (along with DownloadBegin) to disable (and enable) the StopCmd button.

Handling Errors

One important facet of creating a new control is properly handling errors. Try an experiment: Find the GoBack method, and comment out the "On Error Resume Next" statement. Then comment out the CommandStateChange event handler. Next, run the sample program (available electronically; see "Programmer's Services, page 3) and immediately press the back button. The result is not very pretty (see Figure 8) and is certainly something an end user should never see.

The "On Error Resume Next" statement prevents the user from seeing the error dialog. Instead, your code has to check the Err object (unless you just want to ignore the error). If Err.Number is zero, no error occurred. Err is a global object. You don't need to create it or worry about it in any way. Just use it.

The Err object has several other members, but only the Description is usually useful in this context. The Description field, as you might guess, contains the text that describes the error ready to display.

In many cases, you just want to ignore the error anyway. If you wanted to be a stickler for details, you could note each error code you expect, and report only errors you don't expect. However, in this case, just beeping in every case is sufficient.

There is another way you can use "On Error" that might be preferable if you have a large procedure with many possible errors. However, it involves the use of the dreaded "GoTo" statement. Instead of using Example 3(a), you can write Example 3(b) to centralize your error processing.

Of course, many people don't like to use GoTo. Use your own judgment, but VB will let you write "On Error GoTo."

Distributing Components

You'll find an example program that uses the browser control online. It is really nothing more than a form that contains the control and resizes it when the user resizes the form. Since I created both projects, I had no trouble using the control. However, if you distribute a control like this one, watch out for legal pitfalls. Of course, your control needs the Visual Basic run-time DLLs. However, in this case, it also needs Internet Explorer. You can just tell your users that they have to get a copy themselves. You can also arrange with Microsoft (or whatever vendor you've used) to distribute the software with your own. Oddly, you can easily get an arrangement with Microsoft to distribute IE, but not everyone will accommodate you.

Other Changes

You might find it instructive to make a few changes to the browser control. One nice feature would be properties that set the pictures to use for each button. If the properties are empty, you could use the original bitmaps. You also might want to try exposing more of the WebBrowser events to allow the container more options when interacting with the browser.

A Final Thought on the Web

Have you ever wondered about the Nobel peace prize? I always wonder about odd things that no one else seems to pay much attention to. For instance, it always bothered me that there is an Absorbine Jr. What the heck is Absorbine Sr.? (It turns out plain Absorbine is horse liniment.)

I recently had a chance to ask a Rabbi why you always see signs in Baskin Robbins stores that say "All of our products are Kosher except for those containing miniature marshmallows." Oddly, no one I've asked at Baskin Robbins over the years seemed to know. There seems to be no end to the amount of odd trivia for me to wonder about. Years ago I heard about the Nobel winners on the news, and it got my curiosity going.

Alfred Nobel, the man who set up the prize, invented dynamite (look it up at Poor Alfred, he thought he had assured the destruction of the world, and was quite depressed. He set up his awards to encourage acts of peace to atone for his invention. Of course, in retrospect, dynamite isn't so bad. Truthfully, dynamite can be used for good and ill. Dynamite is neither good nor bad; people are.

The World Wide Web isn't inherently good or bad. There are many interesting, informative sites. There are even more bland, mediocre sites. There are plenty of sites most folks would find offensive. There are even more sites that announce the creator's preference in pizza, movies, and music (as though we care).

When is the last time you saw a web site that you thought was culturally important? Have you seen a site that fosters greater international understanding and world peace? I'm sure there must be some sites like this, but not many.

Perhaps a WWW "Nobel" award would be in order. The Web can be a powerful tool for social change, or a powerful waste of telecommunications bandwidth. As web developers, I suppose it is up to us.


Okay, so I didn't invent the Web. I didn't even write a web browser. Thanks to ActiveX and VB5 I can still pretend that I did. Simple components can combine to create fantastic creations. Just look at Tinkertoys, or UNIX shell programming. Let me know what you've created lately.


Listing One

VERSION 5.00Object = "{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}#1.0#0"; "SHDOCVW.DLL"
Begin VB.UserControl Browser 
   ClientHeight    =   5748
   ClientLeft      =   0
   ClientTop       =   0
   ClientWidth     =   7740
   PropertyPages   =   "browser.ctx":0000
   ScaleHeight     =   101.388
   ScaleMode       =   6  'Millimeter
   ScaleWidth      =   136.525
   Begin SHDocVwCtl.WebBrowser WebBrowser 
      Height          =   4092
      Left            =   0
      TabIndex        =   1
      Top             =   1080
      Width           =   7452
      Object.Height          =   341
      Object.Width           =   621
      AutoSize        =   0
      ViewMode        =   1
      AutoSizePercentage=   0
      AutoArrange     =   -1  'True
      NoClientEdge    =   -1  'True
      AlignLeft       =   0   'False
   Begin VB.CommandButton FwdCmd 
      Height          =   372
      Left            =   1800
      Style           =   1  'Graphical
      TabIndex        =   9
      ToolTipText     =   "Go Forward"
      Top             =   120
      Width           =   972
   Begin VB.CommandButton BackCmd 
      Height          =   372
      Left            =   840
      Style           =   1  'Graphical
      TabIndex        =   8
      ToolTipText     =   "Go Back"
      Top             =   120
      Width           =   972
   Begin VB.CommandButton SearchCmd 

      Height          =   372
      Left            =   6600
      Style           =   1  'Graphical
      TabIndex        =   7
      ToolTipText     =   "Search"
      Top             =   240
      Width           =   972
   Begin VB.CommandButton HomeCmd 
      Height          =   372
      Left            =   5400
      Style           =   1  'Graphical
      TabIndex        =   6
      ToolTipText     =   "Return Home"
      Top             =   240
      Width           =   972
   Begin VB.CommandButton StopCmd 
      Enabled         =   0   'False
      Height          =   372
      Left            =   4200
      Style           =   1  'Graphical
      TabIndex        =   5
      ToolTipText     =   "Stop"
      Top             =   240
      Width           =   972
   Begin VB.CommandButton RefreshCmd 
      Height          =   372
      Left            =   3000
      Style           =   1  'Graphical
      TabIndex        =   4
      ToolTipText     =   "Refresh"
      Top             =   240
      Width           =   972
   Begin VB.TextBox Url 
      Height          =   288
      Left            =   0
      TabIndex        =   2
      Top             =   840
      Width           =   7332
   Begin VB.PictureBox Logo 
      AutoSize        =   -1  'True
      Height          =   816
      Left            =   0
      ScaleHeight     =   768
      ScaleWidth      =   768
      TabIndex        =   0
      Top             =   0
      Width           =   816
   Begin VB.Label Status 
      Caption         =   "Initializing"
      Height          =   252
      Left            =   0
      TabIndex        =   3
      Top             =   5520
      Width           =   7452
Attribute VB_Name = "Browser"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Option Explicit
'Event Declarations:
Event TitleChange(ByVal Text As String) 
Enum BRStatusType
  brShowStatus = True
  brHideStatus = False
End Enum

Private Sub BackCmd_Click()
End Sub

Private Sub FwdCmd_Click()
End Sub

Private Sub HomeCmd_Click()
End Sub

Private Sub RefreshCmd_Click()
On Error Resume Next
If Err.Number <> 0 Then Beep
End Sub

Private Sub SearchCmd_Click()
End Sub

Private Sub StopCmd_Click()
On Error Resume Next
If Err.Number <> 0 Then Beep
End Sub

Private Sub Url_KeyPress(KeyAscii As Integer)
If KeyAscii = 13 Then
  On Error Resume Next
  WebBrowser.Navigate Url.Text
  If Err.Number <> 0 Then Beep
  KeyAscii = 0
End If
End Sub
Private Sub SetButton(b As CommandButton, n As Integer)
b.Picture = LoadResPicture(n, vbResBitmap)
b.Height = b.Picture.Height / 100
b.Width = b.Picture.Width / 100
End Sub

Private Sub UserControl_Initialize()
Logo.Picture = LoadResPicture(20, vbResBitmap)
SetButton HomeCmd, 10
SetButton StopCmd, 11
SetButton SearchCmd, 12
SetButton RefreshCmd, 13
SetButton BackCmd, 14
SetButton FwdCmd, 15

Url.Text = ""
WebBrowser.Navigate Url.Text
End Sub
' When you resize, lots goes on
Private Sub UserControl_Resize()
Const offset = 1  ' 1 mm margins
' Set Logo to top left corner
Logo.Top = 0
Logo.Left = 0
' Reposition everything relative to Logo
RefreshCmd.Top = offset
RefreshCmd.Left = ScaleWidth / 2
StopCmd.Top = offset
StopCmd.Left = RefreshCmd.Left + RefreshCmd.Width + offset
HomeCmd.Top = offset
HomeCmd.Left = StopCmd.Left + StopCmd.Width + offset
SearchCmd.Top = offset
SearchCmd.Left = HomeCmd.Left + HomeCmd.Width + offset
BackCmd.Top = offset
BackCmd.Left = Logo.Width + offset
FwdCmd.Top = offset
FwdCmd.Left = BackCmd.Left + BackCmd.Width + offset

Url.Top = Logo.Height + offset
Url.Left = 0
Url.Width = ScaleWidth
WebBrowser.Left = 0
WebBrowser.Top = Url.Height + Logo.Height + offset
WebBrowser.Width = ScaleWidth
WebBrowser.Height = ScaleHeight - WebBrowser.Top - Status.Height
Status.Left = 0
Status.Top = ScaleHeight - Status.Height
Status.Width = ScaleWidth
End Sub

Private Sub WebBrowser_CommandStateChange(ByVal Command As Long, 
                                                     ByVal Enable As Boolean)
Select Case Command
    FwdCmd.Enabled = Enable
    BackCmd.Enabled = Enable
End Select
End Sub

Private Sub WebBrowser_DownloadBegin()
StopCmd.Enabled = True ' Let user stop
End Sub

Private Sub WebBrowser_DownloadComplete()
' Reset logo and Disable stop button
Logo.Picture = LoadResPicture(20, vbResBitmap)
StopCmd.Enabled = False
End Sub

Private Sub WebBrowser_ProgressChange(ByVal Progress As Long, 
                                                 ByVal ProgressMax As Long)
Static Logonum As Integer
' As progress is made, change logo image
Logonum = Logonum + 1
If Logonum = 3 Then Logonum = 0
Logo.Picture = LoadResPicture(20 + Logonum, vbResBitmap)
End Sub

Private Sub WebBrowser_StatusTextChange(ByVal Text As String)
If Text <> "" Then Status.Caption = Text
End Sub
Public Property Get BackColor() As OLE_COLOR
Attribute BackColor.VB_Description = "Returns/sets the background 
                      color used to display text and graphics in an object."
Attribute BackColor.VB_ProcData.VB_Invoke_Property = ";Appearance"
Attribute BackColor.VB_UserMemId = -501
    BackColor = UserControl.BackColor
End Property

Public Property Let BackColor(ByVal New_BackColor As OLE_COLOR)
    UserControl.BackColor() = New_BackColor
    PropertyChanged "BackColor"
End Property

Public Property Get ForeColor() As OLE_COLOR
Attribute ForeColor.VB_Description = "Returns/sets the 
             foreground color used to display text and graphics in an object."
Attribute ForeColor.VB_ProcData.VB_Invoke_Property = ";Appearance"
Attribute ForeColor.VB_UserMemId = -513
    ForeColor = UserControl.ForeColor
End Property

Public Property Let ForeColor(ByVal New_ForeColor As OLE_COLOR)
    UserControl.ForeColor() = New_ForeColor
    PropertyChanged "ForeColor"
End Property

Public Property Get Enabled() As Boolean
Attribute Enabled.VB_Description = "Returns/sets a value that 
           determines whether an object can respond to user-generated events."
Attribute Enabled.VB_ProcData.VB_Invoke_Property = ";Behavior"
Attribute Enabled.VB_UserMemId = -514
    Enabled = UserControl.Enabled
End Property

Public Property Let Enabled(ByVal New_Enabled As Boolean)
    UserControl.Enabled() = New_Enabled
    PropertyChanged "Enabled"
End Property

Public Property Get BackStyle() As Integer
Attribute BackStyle.VB_Description = "Indicates whether a Label 
                       or the background of a Shape is transparent or opaque."
Attribute BackStyle.VB_ProcData.VB_Invoke_Property = ";Appearance"
Attribute BackStyle.VB_UserMemId = -502
    BackStyle = UserControl.BackStyle
End Property

Public Property Let BackStyle(ByVal New_BackStyle As Integer)
    UserControl.BackStyle() = New_BackStyle
    PropertyChanged "BackStyle"
End Property

Public Property Get BorderStyle() As Integer
Attribute BorderStyle.VB_Description = "Returns/sets the border 
                                                    style for an object."
Attribute BorderStyle.VB_ProcData.VB_Invoke_Property = ";Appearance"
Attribute BorderStyle.VB_UserMemId = -504
    BorderStyle = UserControl.BorderStyle
End Property

Public Sub Refresh()
Attribute Refresh.VB_Description = "Forces a complete repaint of a object."
Attribute Refresh.VB_UserMemId = -550
End Sub

Public Sub GoSearch()
Attribute GoSearch.VB_Description = "Go Search Page."
    On Error Resume Next
    If Err.Number <> 0 Then Beep
End Sub

Public Sub GoHome()
Attribute GoHome.VB_Description = "Go home/start page."
    On Error Resume Next
    If Err.Number <> 0 Then Beep
End Sub

Public Sub GoForward()
Attribute GoForward.VB_Description = "Navigates to the next item 
                                                        in the history list."
    On Error Resume Next
    If Err.Number <> 0 Then Beep
End Sub

Public Sub GoBack()
Attribute GoBack.VB_Description = "Navigates to the previous item 
                                                     in the history list."
    On Error Resume Next
    If Err.Number <> 0 Then Beep
End Sub

Public Property Get LocationURL() As String
Attribute LocationURL.VB_Description = "Gets the full URL/path 
                                                          currently viewed."
    LocationURL = WebBrowser.LocationURL
End Property

Public Property Get LocationName() As String
Attribute LocationName.VB_Description = "Gets the short (UI-friendly) name 
                                           of the URL/file currently viewed."
    LocationName = WebBrowser.LocationName
End Property

Public Sub Navigate(Url As String, Optional Flags As Variant, Optional 
          TargetFrameName As Variant, Optional PostData As Variant, 
          Optional Headers As Variant)
Attribute Navigate.VB_Description = "Navigates to a URL or file."
    On Error Resume Next
    WebBrowser.Navigate Url, Flags, TargetFrameName, PostData, Headers
    If Err.Number <> 0 Then Beep
End Sub

Public Property Get ShowStatus() As BRStatusType
Attribute ShowStatus.VB_Description = "Set to True if browser 
                                                 should show status messages"
Attribute ShowStatus.VB_ProcData.VB_Invoke_Property = ";Appearance"
    ShowStatus = Status.Visible
End Property

Public Property Let ShowStatus(ByVal New_ShowStatus As BRStatusType)
    Status.Visible = New_ShowStatus
    PropertyChanged "ShowStatus"
End Property

Private Sub WebBrowser_TitleChange(ByVal Text As String)
    RaiseEvent TitleChange(Text)
End Sub

'Initialize Properties for User Control
Private Sub UserControl_InitProperties()
    End Sub

'Load property values from storage
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)

    UserControl.BackColor = PropBag.ReadProperty("BackColor", &H80000005)
    UserControl.ForeColor = PropBag.ReadProperty("ForeColor", &H80000008)
    UserControl.Enabled = PropBag.ReadProperty("Enabled", True)
    UserControl.BackStyle = PropBag.ReadProperty("BackStyle", 1)
    Status.Visible = PropBag.ReadProperty("ShowStatus", True)
End Sub

'Write property values to storage
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)

    Call PropBag.WriteProperty("BackColor", UserControl.BackColor, &H80000005)
    Call PropBag.WriteProperty("ForeColor", UserControl.ForeColor, &H80000008)
    Call PropBag.WriteProperty("Enabled", UserControl.Enabled, True)
    Call PropBag.WriteProperty("BackStyle", UserControl.BackStyle, 1)
    Call PropBag.WriteProperty("ShowStatus", Status.Visible, True)
End Sub

Back to Article

Listing Two

10 BITMAP home.bmp11 BITMAP stop.bmp
12 BITMAP search.bmp
13 BITMAP refresh.bmp
14 BITMAP lhand.bmp
15 BITMAP rhand.bmp
20 BITMAP logor.bmp
21 BITMAP logog.bmp
22 BITMAP logob.bmp


Back to Article

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.