This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
Everything Doesn't Happen at Once: Loosely Coupled Events
Peter Vogel
If you're running Access on a Windows 2000 computer, you can take advantage
of COM+ to build more sophisticated applications. Peter Vogel looks at using
Loosely Coupled Events to create applications that run asynchronously.
Not everything in your application has to happen at the same time. In fact,
applications that require all of their components to be online and available at
the same time are more difficult to maintain and demand more resources than
applications that can be segmented. If you can break your application up so that
some processing can be "de-coupled" from the rest of the application,
you can gain some significant benefits. The object is to have parts of your
application run asynchronously, allowing components of your application to
respond to requests from the other parts of your system at some convenient time.
For instance, a sales order application might accept orders all day without
making any updates to support shipping the goods that have been ordered.
Sometime after the sales order system shuts down, the portion of the application
that does the shipping updates could run and complete the processing. There are
four major benefits to this kind of design:
- The order system can continue to run even if the shipping database
isn't available.
- Contention problems over the data are reduced because updates are
deferred until data is available.
- Response times on the front end of the system (the user interface) are
improved because less is being done during data entry.
- Shipping updates can be done during off hours to red0uce demands on
hardware.
The last benefit is important because it allows your application to be more
scalable. You might have orders being entered at the rate of several dozen per
second at your peak hours. However, the de-coupled shipping process could run
along behind the order entry process, falling behind during the peaks but
catching up with the orders during the slow periods. The load on your computer
is distributed more evenly over the day.
QC, LCE, MSMQ
In Windows 2000 with COM+, building this kind of functionality into
your Access application is easy. COM+ provides two services that allow you to
de-couple portions of your system and implement asynchronous processing: Queued
Components (QCs) and Loosely Coupled Events (LCEs).
You can achieve much of the functionality of QCs and LCEs by using Microsoft
Message Queue (MSMQ). However, QCs and LCEs let you accomplish the same things
as MSMQ with much less effort. To use MSMQ directly, you have to learn how to
use the MSMQ objects to create a message and put it on a queue. You also have to
create a listener program to process your messages—something that often
requires creating an NT service. With QCs and LCEs, you just need a little
Visual Basic and, thanks to VBA being the programming language for both Access
and Visual Basic, you should feel right at home.
A QC is an object that you can create, call its methods, and release without
the object ever actually being loaded into memory. Instead, a message is placed
on an MSMQ queue for later processing. At some later time, COM+ will then load
the object into memory, call the requested method, and release the object. There
are two problems with QCs: You need MSMQ, and you have to initiate processing of
the queued messages.
LCEs, on the other hand, are almost a free gift from COM+. You create an LCE
object using the New keyword, exactly as you'd create any other object. With the
object created, you call the object's methods, passing whatever parameters you
want. You then set the object variable to Nothing to destroy the object. After
you release the object variable, COM+ will create the object and run the methods
you requested. This code creates an LCE, calls a method, and releases it:
Dim objLCE As Ship.LCEComponent
Set objLCE = New Ship.LCEComponent
objLCE.UpdateShip strCustNo, strOrderNo
Set objLCE = Nothing
If this code looks like the code you'd use to call an ordinary component,
you're right—it is. From the programmer's point of view, an LCE is
indistinguishable from an ordinary component. The LCE can then start up Access
and run the de-coupled portion of your application.
There are two limitations with LCEs. The major limitation is design: You must
have an application whose components can be run independently of each other. The
other limitation is that the communication between your Access application and
the LCE is one-way: You can pass data to the LCE, but you can't have the LCE
return data to you. After all, by the time the LCE actually runs, your
application might have completely shut down.
Creating an LCE
Creating an LCE is relatively straightforward. First, in Visual
Basic, you must create an ActiveX DLL project. I gave my project the name Ship.
You then need to use a Class module to define the interface that your LCE will
implement. Defining the interface begins by giving the Class module the name
that you want to use for your LCE (in my case, that's LCEComponent). The next
step is to write the methods that make up the LCE's interface. A method is just
a subroutine, declared as Public, in a Class module. This code declares the
UpdateShip method that I used in my sample code:
Public Subroutine UpdateShip( _
ByVal CustomerNumber As String, _
ByVal OrderNumber As String)
End Sub
To support the limitations of an LCE, the method must be a subroutine
(because an LCE can't return a value), and its parameters must be declared ByVal
instead of the default ByRef (again, because values can't be returned from the
LCE).
You don't put your code in the Class module that defines your interface.
While that Class module is the one that your application will use when working
with your LCE, you actually put the code for the methods for your LCE in a
separate Class. While your application refers to the Class with the interface,
when it comes time to execute your LCE's code, COM+ will load the Class module
with the code and execute it.
LCEs separate the code from the interface for a simple reason: It allows you
to execute several different routines when an application calls a single LCE
method. COM+ will load and execute all of the different implementations of any
LCE interface. This leads to another way of using LCEs.
When you write an application, you can define an LCE and have your
application call it but never write the code that will execute. Instead, other
developers who want to integrate with your application can write code to be run
when your application calls the methods of an LCE. When your application calls
the methods of the LCE, none, one, or many components that implement that
interface may execute. Using LCEs allows others to integrate their processing
with your application.
Implementing an LCE interface is easy to do. First, you add another Class
module to your Visual Basic project. You then add an Implements statement to the
new Class module that tells Visual Basic that you want to implement your LCE
interface. Since the name that I gave the Class module that defined my LCE
interface was LCEComponent, this is the line I use:
Implements LCEComponent
The next step is to add the methods of the interface to the new Class module.
These methods must include the name of the interface that they're to implement.
To implement the UpdateShip method that I defined in the LCEComponent Class
module, I'd write this code:
Public Subroutine LCEComponent_UpdateShip( _
ByVal CustomerNumber As String, _
ByVal OrderNumber As String)
End Sub
Finally, you add the code that implements your method to the Class module
that implements the LCE interface. The name of this Class doesn't matter because
your application never uses it directly (I called mine Ship1). Assuming that the
code to do the shipping updates is already part of my Access application, the
only thing that I needed to do is call the appropriate routines in my Access
project. Sample code to load Access, open an MDB file, and call a subroutine in
the project would look like this (you'll need to add Access to your Visual Basic
project's References list to make this work):
Dim acc As Access.Application
Set acc = New Access.Application
acc.OpenCurrentDatabase "LCEDemo.MDB"
acc.Run LCEDemo.PurchaseUpdate _
CustomerNumber, OrderNumber
acc.CloseCurrentDatabase
acc.Quit
Set acc = Nothing
The two parts of the application are now de-coupled. The front end of the
application will call the UpdateShip method of the LCEComponent, passing
whatever information is required. Sometime after that, all of the Class modules
that implement the LCE interface will be loaded into memory and executed. The
sample code that calls the PurchaseUpdate routine in the LCEDemo method will
then execute the back end of the database, using the information passed from the
front end.
Setting up an LCE
All through this article, I've been telling you that an LCE component
looks exactly like a standard Visual Basic object. And it does—to the
programmer. However, to make the component an LCE, it must be set up in Windows
2000 Component Services. It's the process of setting the component up in
Component Services that converts a standard ActiveX DLL into an LCE.
To begin, select Start | Programs | Administrative Tools | Component
Services. Expand Component Services to see the Computers folder, expand the
Computers folder to see My Computer, and then expand that item to see the COM+
Applications folder (see Figure 1). Right-click on the
COM+ Applications folder and select New | Application to start creating a COM+
application for your LCE. Just click the Next button in the Wizard that appears,
select Create an Empty Application on the second screen, and give your
application a name.
After your application is created, right-click on the Components folder that
it will contain and select New | Component. The Wizard that appears will walk
you through the process of adding your LCE to the application. After clicking on
the Next button, the second form in the Wizard will offer you three choices.
Selecting "Install new event class(es)" lets you set up an LCE.
Clicking on that button brings up the screen that will let you add DLLs to your
application. Since I had a single DLL that contained both my interface
definition and my implementation, I only needed to add it. In
Figure 2, you can see the result of adding the DLL I've
described here.
After your component has been added, you'll see entries for your interface
class and for the classes that implemented your interface. You can expand the
interface class to reveal a Subscriptions folder, where you'll specify which
objects to execute when some application calls your LCE interface. To assign
components to the interface, right-click on the interface object's Subscriptions
folder and select New | Subscription. This final Wizard will let you first
select the LCE interface and then select all of the components to be run when
the interface is called. With that, your application is ready to run
asynchronously.
The benefits of de-coupling the parts of your application can be valuable.
Even if you don't want to implement your LCE, just calling an LCE in your
application can allow others to integrate their processing with your
application. And, as you've seen, thanks to COM+ and Windows 2000, making it all
happen is simple.
To find out more about Smart Access and Pinnacle Publishing, visit their website at
http://www.pinpub.com/html/main.isx?sub=57
Note: This is not a Microsoft Corporation website. Microsoft is not responsible for its content.
This article is reproduced from the January 2001 issue of Smart Access. Copyright 2001, by Pinnacle Publishing, Inc., unless otherwise noted. All rights are reserved. Smart Access is an independently produced publication of Pinnacle Publishing, Inc. No part of this article may be used or reproduced in any fashion (except in brief quotations used in critical articles and reviews) without prior consent of Pinnacle Publishing, Inc. To contact Pinnacle Publishing, Inc., please call 1-800-493-4867 x4209.