Q How can I code MicroStation VBA to run something automatically? Specifically …
Questions similar to these, posed by MDL and VBA developers, appear on the Bentley Discussion Groups, typically the VBA discussion group.
Q How can I load my VBA application automatically?
A
You can load your VBA project automatically by adding it to the list of startup projects in
configuration variable MS_VBAAUTOLOADPROJECTS
or MS_VBAREQUIREDPROJECTS
.
See VBA help for an explanation of those rather similar variables.
For the example DGN file event handler described here, the line in the user or project configuration file looks like this …
MS_VBAAUTOLOADPROJECTS = OpenCloseEventHandler
Q How can I do something when a user opens or closes a DGN file?
A MicroStation VBA provides a standard Visual Basic mechanism that lets you handle file events. An event, for our purposes, occurs when a user opens or closes a DGN file. From the programmer's perspective, an event is something that happens outside the usual flow of your program. The technical term is that an event is asynchronous.
We're using a few new jargon words here, so you should expect the implementation to be a little unusual as well. To handle asynchronous events, you need an event handler. MicroStation VBA lets you define an event handler in a class module. The key to this implementation is the following line of code …
Private WithEvents hooks As Application
The keyword WithEvents
tells VBA that this class is an event handler.
The statement assigns the variable hooks
as a reference and associates it with the Application
,
which in this case is MicroStation.
VBA automatically creates two subroutines hooks_OnDesignFileClosed
and hooks_OnDesignFileOpened
.
They are known as hooks or callbacks or callback functions,
because MicroStation calls your code when that named event occurs.
Here's the complete code of a class clsOpenClose
that provides an event handler …
Option Explicit' --------------------------------------------------------------------- ' Setup this class as a DGN open/close event handler
Private WithEvents hooks As Application' ---------------------------------------------------------------------
Private Sub Class_Initialize() Set hooks = Application Debug.Print "clsOpenClose initialised" End Sub' ---------------------------------------------------------------------
Public Sub hooks_OnDesignFileClosed(ByVal fileName As String) Debug.Print "Closed design file " & fileName End Sub' ---------------------------------------------------------------------
Public Sub hooks_OnDesignFileOpened(ByVal fileName As String) Debug.Print "Opened design file " & fileName End Sub' ---------------------------------------------------------------------
Now you need a way to create an instance of your clsOpenClose
class.
One place to do this is in your program's main entry point.
Usually, the main entry point is simply a public subroutine Main
.
Use the Set
and New
keywords to create a new instance of the class …
Set oOpenCloseHandler = New clsOpenClose
But there's a problem.
Part of the problem is that the VBA help section about design file events doesn't tell the full story.
Where should you declare the variable oOpenCloseHandler
?
If you do this …
Sub Main () Dim oOpenCloseHandler As clsOpenClose Set oOpenCloseHandler = New clsOpenClose End Sub
Local variable oOpenCloseHandler
is created and then destroyed immediately when Main
exits.
So your event handler started and then terminated: it was no more than a warm summer zephyr.
The solution is to declare your variable at Module scope: that way it hangs around while your project is loaded …
Private m_oOpenClose As clsOpenClose
Now instantiate the variable in Main
, and your class instance will stay alive until the project is unloaded …
Private m_oOpenClose As clsOpenClose Sub Main () Set m_oOpenClose = New clsOpenClose End Sub
Another way to start the event handler is to add a subroutine named OnProjectLoad
.
When MicroStation first loads a project, it looks for a subroutine named OnProjectLoad
and, if it exists,
executes it.
Since you can load a project automatically, this provides a way to load and run your event handler code automatically.
Thanks to Duncan Macdonald at PLP Architects in London for digging that nugget from Ask Inga.
In this example, OnProjectLoad
is no different to Main
…
' ---------------------------------------------------------------------
' OnProjectLoad, if it exists in your module, is run automatically
' when your VBA project is loaded into MicroStation. You can tell
' MicroStation to load VBA projects automatically using the configuration
' variable MS_VBAAUTOLOADPROJECTS
'
' In this example project, OnProjectLoad simply sets a reference in the
' member variable m_oOpenClose to a new instance of clsOpenClose
' ---------------------------------------------------------------------
Public Sub OnProjectLoad()
Set m_oOpenClose = New clsOpenClose
End Sub
Clearly this example event handler doesn't do anything useful.
The Debug.Print
statements give you a log (in VBA's Immediate window) of the events as they are handled …
clsOpenClose initialised Closed design file D:\temp\point-Test2d.dgn Opened design file L:\test.dgn Closed design file L:\test.dgn Opened design file D:\temp\lstring.dgn
You can download the event handler VBA project.
Unpack OpenCloseEventHandler.zip
, which contains OpenCloseEventHandler.mvba
.
Copy the .mvba
file to one of the Bentley folders in the MS_VBASEARCHDIRECTORIES
configuration variable.
Assuming you have a default installation of MicroStation V8.5, that folder might be
C:\Program Files\Bentley\Workspace\Projects\Standards\vba
.
Load the project in the usual way, and OnProjectLoad
is run automatically.
Load the project automatically, and OnProjectLoad
is run automatically.
You could also run Main
to initialise your event handler, but it's unnecessary.
On loading, you'll see the clsOpenClose initialised
message in VBA's Immediate window.
After that, nothing will happen: you can do things in MicroStation as usual.
However, when you close the current file you will see the Closed design file
message.
When you open a new file you will see the Opened design file
message.
Q How can I do something when a user opens or closes a DGN model?
A A DGN file contains one or more models. Each model contains 2D or 3D geometry and other data. A user can navigate between models using MicroStation's user interface. MicroStation VBA provides a standard Visual Basic mechanism that lets you handle model events. An event, for our purposes, occurs when a user opens or closes a DGN model. From the programmer's perspective, an event is something that happens outside the usual flow of your program. The technical term is that an event is asynchronous.
To observe model events, write a VBA class that Implements IModelActivateEvents
.
Your class should have subroutines BeforeActivate
and AfterActivate
.
Each subroutine is passed a ModelReference
object.
Q How can I tell when MicroStation is doing nothing?
A
The EnterIdle
state informs you when MicroStation's input queue is empty and it is not performing any processing.
It is waiting for user input.
A new MicroStation process does not enter the idle state until it has finished initializing.
A program can use this event to be notified when initialization is complete.
This event can also be useful for an OnDesignFileOpened
event handler that needs to be notified the next time MicroStation becomes idle.
For example, suppose user has just opened a new DGN file.
At the point of opening, it is not safe to assume that all MicroStation's internal data structures are initialised and ready for use.
Writing an EnterIdle
event handler lets you write code that does nothing until MicroStation
is fully initialised.
Once MicroStation is initialised, it enters the idle state;
at that time you can expect its internal data structures to be fully populated and stable.