Recipe 16.7 Create a Custom Smart Tag DLL
16.7.1 Problem
Users of my application
prefer to use datasheet view for browsing data. I'd
like to provide a smart tag that will enable them to open forms and
reports. How can I create a custom smart tag that will allow users to
open a form that shows all orders for a customer as well as open a
report that shows total sales for a customer?
16.7.2 Solution
If you want to provide conditional processing for
smart tag actions then you must
create a smart tag DLL, using Visual Basic 6.0 or Visual Basic .NET.
In this solution, you'll see how you can use
Visual Basic 6.0 to accomplish this.
|
If you prefer, you can use Visual Basic .NET to create the smart tag
DLL. In Chapter 17 you'll learn
how to create .NET programs that can be called by Access. For smart
tags, there is no particular advantage to using Visual Basic .NET and
Visual Basic 6.0 will be more familiar to Access programmers who have
worked with VBA, so we have chosen to use Visual Basic 6.0 for this
example.
|
|
16.7.2.1 Setting up the DLL project
Follow these steps to create the DLL project using Visual Basic 6.0:
Launch Visual Basic 6.0 and create a new DLL project. The sample
application is named AccessSmartTag, and it includes one class,
stActions. The stActions class provides the Actions interface that
defines the smart tag actions you want to take. Add the references shown in Figure 16-10. The
reference to the Microsoft Smart Tags 2.0 Type Library is required.
This example also has a reference to the Microsoft Access 11.0 Object
Library so that you can work with Access objects from your smart tag
code and the Microsoft DAO 3.6 Object Library so that you can work
with data objects.
Place the following statements in the Declarations of the stActions
class. You do not need a Recognizer interface for a smart tag
that is designed to work exclusively with Access: Option Explicit
Implements ISmartTagAction
Implements ISmartTagAction2 The next step is to implement the smart tag action interface by
creating properties and methods that describe the smart tag action
DLL. Most of these properties are fairly straightforward and just
return a requested string. The ISmartTagAction_ProgId( ) is the
language-independent unique identifier that corresponds to the ProgID
of the DLL class. In this example, the name of the project is
AccessSmartTag, and the class name is stActions: Private Property Get ISmartTagAction_ProgId( ) As String
ISmartTagAction_ProgId = "AccessSmartTag.stActions"
End Property The ISmartTagAction_Name property is a short phrase that describes
the DLL: Private Property Get ISmartTagAction_Name(ByVal lcid As Long) As String
ISmartTagAction_Name = "Demo Smart Tag Actions"
End Property The ISmartTagAction_Desc property is a longer description of the DLL: Private Property Get ISmartTagAction_Desc(ByVal lcid As Long) As String
ISmartTagAction_Desc = _
"This is a Sample SmartTag used to open Forms and Reports."
End Property The ISmartTagAction_SmartTagCount property reflects the number of
smart tag types. This example contains one smart tag, so the count is
1: Private Property Get ISmartTagAction_SmartTagCount( ) As Long
ISmartTagAction_SmartTagCount = 1
End Property Each smart tag type is defined by a namespace to keep it unique,
which is defined in the ISmartTagAction_SmartTagName property.
SmartTag type names are always in the format of namespaceURI#tagname.
In this example, the (ismarttag = 1) condition isn't
strictly necessary since there is only one smart tag type defined,
but this shows a pattern you could use for handling multiple types: Private Property Get ISmartTagAction_SmartTagName(ByVal ismarttag As Long) As String
If (ismarttag = 1) Then
ISmartTagAction_SmartTagName = _
"schemas-microsoft-com/smarttag/northwind#openform"
End If
End Property The ISmartTagAction_SmartTagCaption property allows you to specify
the caption that will be used: Private Property Get ISmartTagAction_SmartTagCaption( _
ByVal ismarttag As Long, ByVal lcid As Long) As String
ISmartTagAction_SmartTagCaption = "Access Smart Tag Demo"
End Property The ISmartTagAction_VerbCount is where you specify the number of
verbs in the smart tag. In this example, there are two actions that
the smart tag can take: opening a form or opening a report: Private Property Get ISmartTagAction_VerbCount(ByVal bstrName As String) As Long
If (bstrName = "schemas-microsoft-com/smarttag/northwind#openform") Then
ISmartTagAction_VerbCount = 2
End If
End Property Smart tag action clients will first ask action DLLs for a unique ID
integer for each of the verbs it wants to support, passing in the
name and ordinal number for each one. Generating the unique ID is
totally up to the action DLL, which gives the action DLL more
flexibility. For example, a smart tag action DLL can specify the same
VerbID value for the same action across smart tag types, or it can
use the same VerbID for similar variants of an action. In this
example, the ISmartTagAction_VerbID property returns iVerb (the same
ordinal number passed in) back to the action client as the unique ID: Private Property Get ISmartTagAction_VerbID( _
ByVal bstrName As String, ByVal iVerb As Long) As Long
ISmartTagAction_VerbID = iVerb
End Property The ISmartTagAction_VerbNameFromID property is used internally to
represent the verb ID: Private Property Get ISmartTagAction_VerbNameFromID(ByVal idVerb As Long) _
As String
Select Case idVerb
Case 1
ISmartTagAction_VerbNameFromID = "openCustomers"
Case 2
ISmartTagAction_VerbNameFromID = "openReport"
Case Else
ISmartTagAction_VerbNameFromID = ""
End Select
End Property The code in the ISmartTagAction2_VerbCaptionFromID2 property checks
the VerbID and then uses the "///"
syntax to get cascading menus in the smart tag. Figure 16-11 shows the results when the smart tag is
accessed in the client application: Private Property Get ISmartTagAction2_VerbCaptionFromID2( _
ByVal VerbID As Long, ByVal ApplicationName As String, _
ByVal LocaleID As Long, ByVal Properties As SmartTagLib.ISmartTagProperties, _
ByVal Text As String, ByVal Xml As String, ByVal Target As Object) As String
If (VerbID = 1) Then
ISmartTagAction2_VerbCaptionFromID2 = _
"Smart Tag Actions///Open Customer Form"
ElseIf (VerbID = 2) Then
ISmartTagAction2_VerbCaptionFromID2 = _
"Smart Tag Actions///Open Customer Report"
End If
End Property
The ISmartTagAction2_InvokeVerb2 method provides code to perform the
actions that the smart tag takes. The first section of the code sets
a variable to point to the Target, which is the Access control object
passed in. If the smart tag is defined on a Table object instead of a
form control, then Access creates a control under the covers that
gets passed to the smart tag DLL: Private Sub ISmartTagAction2_InvokeVerb2( _
ByVal VerbID As Long, ByVal ApplicationName As String, _
ByVal Target As Object, ByVal Properties As SmartTagLib.ISmartTagProperties, _
ByVal Text As String, ByVal Xml As String, ByVal LocaleID As Long)
On Error GoTo HandleErr:
Dim cb As Access.Control
Set cb = Target The next block of code validates that the control source is
CustomerID. If not, a MsgBox statement provides feedback to the user
that the smart tag only works when attached to the CustomerID. If the
smart tag is attached to CustomerID, the code gets a reference to the
Access.Application object from the Target's
Application property: If cb.ControlSource <> "CustomerID" Then
MsgBox "This action only works if you run it on the Customer ID field.", _
vbOKOnly, "Smart Tag Error"
GoTo ExitHere
Else
Dim app As Access.Application
Set app = cb.Application
End If The code then branches based on VerbID. If the VerbID is 1, then the
code sets a reference to the Application object's
CurrentDb property to gain access to DAO objects. This allows the
code to execute a query to obtain the total number of orders for a
given CustomerID. This is then retrieved into a DAO Recordset, and
passed to the Customers form as an OpenArgs argument: If VerbID = 1 Then
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = app.CurrentDb
Dim strQry As String
Dim strOrders As String
strQry = "SELECT Count(*) AS NumOrders FROM Orders WHERE CustomerID='" _
& cb.Value & "';"
Set rs = db.OpenRecordset(strQry)
If Not rs.EOF Then
strOrders = "Total number of orders: " & rs!NumOrders
Else
strOrders = "No orders for this customer"
End If
rs.Close
app.DoCmd.OpenForm "Customers", _
WhereCondition:="[CustomerID] = '" & cb.Value & "'", _
OpenArgs:=strOrders If the second action is chosen, then the code opens rptCustomers
report, passing the CustomerID as the WhereCondition argument
(without this WhereCondition, the report would open displaying all
the customers): ElseIf VerbID = 2 Then
app.DoCmd.OpenReport "rptCustomers", _
View:=acViewPreview, _
WhereCondition:="[CustomerID] = '" & cb.Value & "'"
End If The error handling code is mainly useful for debugging. It displays
any error information in a MsgBox statement: ExitHere:
Exit Sub
HandleErr:
MsgBox Err.Number & " " & Err.Description, _
vbCritical, "Error in AccessSmartTag.ISmartTagAction2_InvokeVerb2"
Resume ExitHere
End Sub
16.7.2.2 Compiling and registering the DLL project
Once you've written the code, build the
DLL project by choosing File
Make AccessSmartTag DLL from the menu. This will create
the correct registry entries. Launch regedit from the Windows Start
Run menu. To obtain the CLSID for the action handler,
navigate to the following node in the Registry:
HKEY_CLASSES_ROOT\AccessSmartTag.stActions\Clsid
Double-click the Clsid node to obtain the value, as shown in Figure 16-12. Copy it to the clipboard and close the
regedit window without saving.
You can then edit the registry directly or create a reg file to
update the registry entries. Use Notepad to create a new file and
name it Reg_AccessSmartTag.reg. The file should contain the following
text. However, you will need to replace the value shown in the curly
braces with the value that you copied to the Clipboard from the
Registry in the previous step:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Actions\
{9F7503BB-4BBA-4A4A-B1A5-A0DF0A0187F5}]
In case you ever need to unregister the smart
tag, create a second file named Unreg_AccessSmartTag.reg. The file
should contain the following text. Again, replace the value shown
here in the curly braces with the value copied to the Clipboard:
Windows Registry Editor Version 5.00
[-HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Actions\
{9F7503BB-4BBA-4A4A-B1A5-A0DF0A0187F5}]
Save both files and double-click Reg_AccessSmartTag.reg. This will
create the entries in the registry so that Access can recognize the
smart tag actions.
Open the 16-07.MDB sample database and open the
Customers form in design view. View the code in the
form's Open event, which displays anything passed in
the OpenArgs event in the form's Caption property:
Private Sub Form_Open(Cancel As Integer)
' Display any OpenArgs in the Caption
Dim str As String
str = Me.OpenArgs & ""
If Len(str) > 0 Then
Me.Caption = str
End If
End Sub
Close the form and open the Customers table in design view. Assign
the smart tag to the CustomerID field, as shown in Figure 16-13.
Save the table and view it in datasheet view. When you choose the
first smart tag action, the Customers form will open with the total
number of orders for the selected customer displayed in the
form's Caption. If you choose the second smart tag
action, then the rptCustomers report will open displaying sales data
for the selected customer.
16.7.3 Discussion
You can write a smart tag DLL in any language that supports writing
COM add-ins. You can also write a smart tag DLL in managed (.NET)
code.
There are two interfaces involved in implementing smart tag actions:
the ISmartTagAction interface and the ISmartTagAction2 interface.
These interfaces provide the client application with the information
needed to support smart tag actions. The ISmartTagAction interface is
compatible with Office XP, and the ISmartTagAction2 interface is
specific to Office 2003, and allows you to tap into new
functionality.
|
You do not need to implement the ISmartTagRecognizer and
ISmartTagRecognizer2 interfaces in a smart tag DLL targeted
specifically for Access because Access does not use recognizers.
|
|
The role of an ISmartTagAction interface is to provide actions for
individual smart tag types. Each smart tag type is defined by a
namespace URI plus its tag name to keep it unique. A
"#" character is appended to the
namespace URI and is used to separate the namespace URI from its tag
name, as shown in this example, where
"schemas-microsoft-com/smarttag/northwind"
is the namespace URI and "openform"
is the tag name. The combination results in the fully qualified name
of the smart tag type. The URI portion of the property name ensures
that it is globally unique and unambiguous, so that two tags with the
same tag name (openform) can be differentiated:
Private Property Get ISmartTagAction_SmartTagName( _
ByVal ismarttag As Long) As String
ISmartTagAction_SmartTagName = _
"schemas-microsoft-com/smarttag/northwind#openform"
End Property
16.7.3.1 Working with the Access object model
The most interesting part of the sample smart tag DLL is that it
shows you how you can work with the Access object model as well as
DAO. The code in the
ISmartTagAction2_InvokeVerb2 method has an input parameter, Target As
Object, which Access uses to pass in the control that has the smart
tag attached. The code then creates an Access.Control variable that
references the Target:
Dim cb As Access.Control
Set cb = Target
Once you have the
Access Control object, you can then set a
variable to point to the Access Application object, giving you full
access to any part of your application:
Dim app As Access.Application
Set app = cb.Application
From there, you can work with the data in your application by
creating a DAO Database object using the Application
object's CurrentDb property:
Dim db As DAO.Database
Set db = app.CurrentDb
The code goes on to open a Recordset based on a query that counts the
total number of orders for the selected customer, writing it to a
String variable. It then opens the form to display the selected
customer and passes that count value in the OpenArgs argument of the
Application object's DoCmd.OpenForm method:
app.DoCmd.OpenForm "Customers", _
WhereCondition:="[CustomerID] = '" & cb.Value & "'", _
OpenArgs:=strOrders
When the Customers form opens, the code in the Open event evaluates
whether any data has been passed in the OpenArgs argument, and then
displays that information in the form's Caption
property. If the form is opened normally without any OpenArgs data
being passed to it, then the default caption is displayed:
Private Sub Form_Open(Cancel As Integer)
Dim str As String
str = Me.OpenArgs & ""
If Len(str) > 0 Then
Me.Caption = str
End If
End Sub
The code for opening a report uses similar techniques. Creating a
smart tag DLL allows you full access to the entire Access object
model, and allows you to create conditional logic for your smart tag.
Smart tags can be a good way to provide extra functionality for users
who prefer working in datasheet view.
16.7.4 See Also
See the Preface for more information on working with DAO to access
data.
|