Hyperlinking
The UserControl object exposes
the Hyperlink property, which returns a Hyperlink object that you can
use to navigate to other HTML pages. The Hyperlink object exposes three methods,
the most important of which is the NavigateTo method:
|
Hyperlink.NavigateTo Target,
[Location], [FrameName]
|
Target is
the URL to which you navigate, Location is an optional argument that points
to a specific location in an HTML page, and FrameName is the optional
name of a frame in a page. If the ActiveX control is running inside a browser,
the new page is shown within the browser itself; if the control isn't running
in a browser, the default browser is automatically launched.
The Hyperlink object exposes
two more methods, GoBack and GoForward, which let you navigate
the browser's history list. Unless you're absolutely sure that the history list
isn't empty, you should always protect these methods with an On Error statement:
Private Sub cmdBack_Click()
On Error Resume Next
Hyperlink.GoBack
If Err Then MsgBox "History is empty!"
End Sub
|
Tip
You can navigate many kinds of documents, not just HTML pages. For example,
Internet Explorer can display Microsoft Word and Microsoft Excel files, so
you can use it as a document browser, as the following code demonstrates:
Hyperlink.NavigateTo "C:\Documents\Notes.Doc
|
Asynchronous
download
ActiveX controls authored
in Visual Basic support asynchronous downloading of properties. Let's say that
you have a PictureBox-like ActiveX control that can read its contents from a
GIF or BMP file. Instead of waiting for the image to be completely downloaded,
you'll do better to start an asynchronous download operation and immediately
return the control to the user. The key to asynchronous downloading is the AsyncRead
method of the UserControl object, whose syntax is this:
AsyncRead Target, AsyncType, [PropertyName],
[AsyncReadOptions]
|
Target is
the URL of the property to be downloaded. AsyncType is the type of the
property and can be one of the following values: 0-vbAsyncTypePicture (an image
that can be assigned to a Picture property), 1-vbAsyncTypeFile (a file
created by Visual Basic), or 2-vbAsyncTypeByteArray (a Byte array). PropertyName
is the name of the property whose value is being downloaded and is useful
when there are many properties that can be downloaded asynchronously. But keep
in mind that there can be only one AsyncRead operation active at one time.
The AsyncRead method
supports a new AsyncReadOptions argument, a bit-fielded integer that accepts
the values listed in Table 17-1. Using this values you can fine-tune the performance
of your asynchronous download operation and decide whether the control can use
the data in the local cache.
Table 17-1.
The
available values for the AsyncReadOptions argument of the AsyncRead method.
|
Constant
|
Value
|
AsyncRead Behavior
|
|
vbAsyncReadSynchronousDownload
|
1
|
Returns only when the down load is complete (synchronous
download).
|
|
vbAsyncReadOfflineOperation
|
8
|
Uses only the locally cached resource.
|
|
vbAsyncReadForceUpdate
|
16
|
Forces the download from the remote Web server, ignoring
any copy in the local cache.
|
|
vbAsyncReadResynchronize
|
512
|
Updates the copy in the local cache only if the version
on the remote Web server is more recent.
|
|
vbAsyncReadGetFromCacheIfNetFail
|
&H80000
|
Uses the copy in the local cache if the connection to
the remote Web server fails.
|
On the companion CD, you'll
find the complete source code of a ScrollablePictureBox ActiveX control, which
supports scrolling of large images as well as their asynchronous downloading
from the Internet. (See Figure 17-19.) The asynchronous download feature is provided
in the form of a PicturePath property that, when assigned, starts the
downloading process:
Public Property Let PicturePath(ByVal New_PicturePath As String)
m_PicturePath = New_PicturePath
PropertyChanged "PicturePath"
If Len(m_PicturePath) Then
AsyncRead m_PicturePath, vbAsyncTypePicture, "Picture"
End If
End Property
You can cancel an asynchronous
download operation at any moment using the CancelAsyncRead method:
|
CancelAsyncRead "Picture"
|
Figure 17-19.
The ScrollablePictureBox control running inside Internet Explorer.
When the asynchronous download
terminates, Visual Basic fires an AsyncReadComplete event in the UserControl
module. This event receives an AsyncProperty object, whose most important properties
are PropertyName and Value:
Private Sub UserControl_AsyncReadComplete(AsyncProp As AsyncProperty)
If AsyncProp.PropertyName = "Picture" Then
Set Image1.Picture = AsyncProp.Value
End If
End Sub
The AsyncProperty object
has been greatly enhanced in Visual Basic 6 and now includes properties such
as BytesMax, ByteRead, Status, and StatusCode. For
additional information, see the language documentation. Visual Basic 6 also exposes
the AsyncReadProgress event, which fires when new data is available locally.
You can use this event to display a progress bar that informs the user about
the status of the operation:
Private Sub UserControl_AsyncReadProgress(AsyncProp As AsyncProperty)
If AsyncProp.PropertyName = "Picture" Then
Dim percent As Integer
If AsyncProp.BytesMax > 0 Then
percent = (AsyncProp.BytesRead * 100&) \ AsyncProp.BytesMax
End If
End If
End Sub
The AsyncReadProgress
and AsyncReadComplete events fire immediately if the data is stored
on a local disk (in this case, PicturePath is the path of a file) or if
it is in the local cache. If you aren't downloading an image (therefore, AsyncProp.AsyncType
is 1-vbAsyncTypeFile or 2-vbAsyncTypeByteArray), you can read and process
the data while it's being downloaded. This arrangement slows the process slightly,
but usually the overhead isn't noticeable. If you open a file, you must close
it before exiting the event procedure, and you must avoid calling DoEvents
to avoid reentrancy problems. The AsyncReadProgress and AsyncReadComplete
events occur when the download is complete: You can learn when this happens in
the AsyncReadProgress event by checking that the AsyncProp.StatusCode
property returns the value 6vbAsyncStatusCodeEndDownloadData.
Accessing the
browser
A control on an HTML page
can do more than simply modify its appearance and behavior: It can manipulate
the attributes of the page itself and of the other controls on it. You can access
the container page using the Parent object, as this code does:
' Changing the HTML page's foreground and background colors
With Parent.Script.document
.bgColor = "Blue"
.fgColor = "White"
End With
You can also access and
manipulate all the controls on the page using the ParentControls collection.
But this method requires that you set the ParentControlsType property
of ParentControls collection to the value vbNoExtender. This setting is necessary
because Internet Explorer exposes an Extender object that can't be used from
Visual Basic code.
I don't have enough room to describe all the things that you can do once you
have a reference to the page that contains the ActiveX control. If you're interested,
you should look for additional information on the Internet Explorer Scripting
Object Model on the Microsoft Web site.
|
Tip
If you're writing a control that can be used on both regular forms and HTML
pages, you need to know which container it's running in. You can do this by
looking at the object returned by the Parent object:
' Test if the control runs in an HTML page.
If TypeName(Parent) = "HTMLDocument" Then ...
|
Show and Hide events
The Show event fires
in the UserControl module when the page that contains it becomes visible, while
the Hide event fires when the page becomes invisible but is still in the
cache. Eventually, the page might become visible again, thus firing another Show
event, or the browser might remove the page from the cache (for example, when
the browser itself is closed), in which case the control receives a Terminate
event.
Multithreaded
ActiveX controls
If you're going to use the
ActiveX control with Microsoft Explorer or a multithreaded Visual Basic application,
you should make the control apartment-threaded by selecting the corresponding
Threading Model option in the General tab of the Project Properties dialog box.
Beware, however, of a documented bug: Multithreaded controls don't fire the Hide
event when they run under Internet Explorer 4.0. For an ActiveX control to behave
correctly, you must mark it as single-threaded and enable the Active Desktop
option. For more information, see article Q175907 of the Microsoft Knowledge
Base.
Component Download
When you're creating an
HTML page that contains one or more ActiveX controls, you must provide a way
for the browser to download and install the ActiveX control if it isn't already
registered on the client machine.
Creating a package
for deployment
The mechanism used for deploying
the ActiveX controls on client machines is based on Cabinet(CAB) files.
CAB files are compressed files that can include multiple ActiveX controls (as
well as other types of files, such as EXEs and DLLs) and that can be digitally
signed if necessary. You create CAB files by running the Package and Deployment
Wizard and selecting Internet Package in its second step. The wizard also creates
a sample HTM file that you can use as a model for the page that will host the
control. This file contains the correct value for the CODEBASE attribute, which
informs the browser of the name of the CAB file and the version of the ActiveX
control. The browser then downloads the CAB file if the control with that CLSID
isn't registered on the client machine or if its version is older than the one
specified in the HTML page. This is a portion of the sample HTML file created
for the ClockOCX control:
<OBJECT ID="Clock"
CLASSID="CLSID:27E428E0-9145-11D2-BAC5-0080C8F21830"
CODEBASE="ClockOCX.CAB#version=1,0,0,0">
</OBJECT>
CAB files can embed all
the ancillary files that the ActiveX control needs to work properly, including
data files and satellite DLLs. The list of dependencies of an ActiveX control
is described in an INF file, which is produced by the Package and Deployment
Wizard and also included in the CAB file itself.
ActiveX controls authored
in Visual Basic also require the Visual Basic runtime files. The default option
in the Package and Deployment Wizard instructs the installing procedure to download
the runtime files from the Microsoft Web site. This setting ensures that the
user always receives the most recent version of those files and also reduces
the burden on your Web site.
Safety
When an ActiveX control
is running in the browser, it could do all sort of evil things to the user's
system, such as deleting system files, trashing the Registry, or stealing confidential
data. You must, therefore, assure users that not only are your controls not so
rude, but also that no other developer can use your controls to damage the machines
they're running on.
To broadcast the promise
that your control doesn't (and can't) misbehave, you can mark it as "Safe
for initialization" or "Safe for scripting." If you declare that
your control is safe for initialization, you're telling the browser that there's
no way for an HTML page author to accidentally or intentionally do any harm by
assigning values to the control's properties through the <PARAM> tags in
the <OBJECT> section of the page. If you mark your control as safe for
scripting, you're going a bit further because you're declaring that there's no
way for a script on the page to set a property or call a method that can damage
the system. By default, Microsoft Internet Explorer refuses to download components
that aren't marked as safe for initialization and safe for scripting.
Marking your control as
safe for initialization or safe for scripting isn't a decision that you should
take lightly. The fact that your control doesn't purposely do any damage isn't
enough in most cases. Just to give you an idea of the subtleties that you must
account for, imagine these scenarios:
-
You provide a method that
lets developers save data to any path. The control isn't safe for scripting
because a malicious developer might use this feature to overwrite important
system files.
-
You decide the location in which a temporary
file is stored, but you leave developers free to write any amount of data to
it. Again, the control isn't safe for scripting because a developer might deliberately
consume all the free space on disk and bring Windows to an abrupt crash.
You mark your component as safe for initialization or safe for scripting in
the Package and Deployment Wizard, as shown in Figure 17-20.
|
Tip
You can quickly learn which ActiveX controls on your machine are safe for
initialization or for scripting by using the OleView utility that comes with
Visual Studio. This is the portion of the Registry that marks a control as
safe:
HKEY_CLASSES_ROOT
\CLS
\<your control's CLSID>
\Implemented Categories
\{7DD95802-9882-11CF-9FA9-00AA006C42C4}
\{7DD95801-9882-11CF-9FA9-00AA006C42C4}
|
The last two lines of the listing indicate safe for initialization and safe
for scripting, respectively. Once you know how this information is recorded
in the Registry, you can use the Regedit utility to modify these setting by
adding or removing these keys.
|
Figure 17-20.
The Package and Deployment Wizard lets you mark your controls as Safe For
Initialization and Safe For Scripting.
A more sophisticated way
to address the safety problem is through the IObjectSafety ActiveX interface,
which allows your component to programmatically specify which methods and properties
are safe. This approach offers greater flexibility than just marking the component
as safe. This is an advanced topic, however, and I won't cover it in this book.