Documente Academic
Documente Profesional
Documente Cultură
LEARNING
MICROSTATION"VBA
bV Jerrv Winters
Learning
MicroStation VBA
Jerry Winters
Bentley, "B" Bentley logo, Bentley Institute Press, and MicroStation are either registered or
unregistered trademarks or servicemarks of Bentley Systems, Incorporated or one of its direct or
indirect wholly-owned subsidiaries. Other brands and product names are trademarks of their
respective owners.
Publisher does not warrant or guarantee any of the products described herein or perform any
independent analysis in connection with any of the product information contained herein.
Publisher d oes not assume, and expressly disclaims, any obligation to obtain and include
information other than that provided to it by the manufacturer.
The reader is expressly warned to consider and adopt all safety precautions that might be indicated
by the activities herein and to avoid all potential hazards. By following the instructions contained
herein, the reader willingly assumes all risks in connection with such instructions.
The publisher makes no representation or warranties of any kind, including but not limited to, the
warranties of fitness for particular purpose of merchantability, nor are any such representations
implied with respect to the material set forth herein, and the publisher takes no responsibility with
respect to such material. The publisher shall not be liable for any special, consequential, or
exemplary damages resulting, in whole or part, from the readers' use of, or reliance upon, this
material.
Published by:
Bentley Institute Press
Bentley Systems, Incorporated
685 Stockton Drive
Exton, PA 19341
www.bentley.com
equally well. With the benefit of Jerry Winters' broad VBA expertise and
his knowledge of MicroStation, that's exactly what this comprehensive
text accomplishes.
The introductory chapters thoughtfully and thoroughly step new users
through the basics of Visual Basic for Applications. From his detailed
review of VBA's Integrated Development Environment, through his
careful consideration of how and when to use forms and class modules,
to his comprehensive explanation of object models, Jerry ensures that
novice users not only have a how-to guide for working with VBA, but
they can also benefit from his insight into how VBA tools can be best
applied to create professional applications for MicroStation.
Expert VBA programmers will likewise find Jerry's book an invaluable
reference tool -- one that will help them exploit what VBA has to offer.
Jerry's overview of XML and the Windows API in MicroStation VBA,
for instance, are sure to improve any programmer's mastery.
But for the masses of MicroStation users, this book should help you
finally put your programming fears to rest. Within these pages, you have
all you need to start programming in MicroStation and automate your
most common tasks.
Contents
iii
iv I Contents I
Help Menu ......... . .... ... .. .... ...... ........... ....... 3-21
Toolbars ........... . ..... . . . . . ......................... . ..... 3-22
Standard toolbar ................ . ................... . ..... 3-22
Edit toolbar . ... ...... ........ .... ..... . ...... . ........... 3-22
Debug toolbar ............... . ........ . .. . . .. . .. .......... 3-22
User Form toolbar ......................................... 3-23
Windows ........................... .. .. ... ... . ... .. ..... . ... 3-23
Project Explorer ............................. . ............ 3-23
Object Browser ................. .. ...... . . . ... .. .......... 3-24
Properties Window ......... .. ............ . ........ . ....... 3-25
Watch Window ........................................... 3-25
Locals Window ........................................... 3-26
Immediate Window ....................................... 3-26
Call Stack Window ........................................ 3-27
Toolbox Window ........ . .. . . ..... . .. ... .. .. . . . ... .... .. . 3-27
Other Windows ..... . ..................... . .... . . .. . . ..... 3-28
Review ... . .... . ............................................. 3-30
Fu nct io n Object
Fu nctionlndex Variable
Keyboard key
xvii
xviii I Introduction I
ACCOMPANYING CD-ROM
The accompanying CD includes all source code referenced in each
chapter of the book. The CD also includes procedures, and addenda to
the book as well as a comprehensive Object Model listing and other
example files such as V8 DGN files, Microsoft Excel spreadsheets,
Microsoft Access databases, and more.
BENTLEY INSTITUTE
The Bentley Institute develops and delivers professional training
programs that are designed to increase the productivity of AEC
professionals. Attend accredited courses at Bentley Institute training
facilities around the world or train on-site at your office location. Train
without travel in virtual classrooms through instructor-led distance
learning and learn any time though OnDemand eLearning. To learn
more, go to http://bentleyinstitute.bentley.com.
ACKNOWLEDGMENTS
I would like to thank the Technical Review Committee of Mark
Anderson, Phil Chouinard and Robert Hook, as well as the Bentley
Institute Press Team of Gilda Cellini, Frank Conforti, Lissa Jennings,
Drew Knox, Scott Lofgren, Maureen Rhoads, and Christopher Rogers,
without whom this book would have never gotten off the ground. I
would like to sincerely thank Graham Steele and Rudi Wells for
reviewing the material in this book and helping to ensure that it is ready
to put into the hands of any MicroStation user.
Furthermore, I would like to thank the Bentley Institute fo r affording
me the opportunity to write about MicroStation's implementation of
VBA. I hope the lessons learned in this book will be as rewarding to the
reader as they have been for me.
xx I Introduction I
1 Introducing VBA
These are five very good questions and they deserve answers.
WHAT IS VBA?
VBA is an abbreviation for Visual Basic for Applications. Microsoft
licenses VBA to companies such as Bentley Systems, Inc., so users can
customize the company's software. Then, companies that develop
world-class software, such as MicroStation, can give their customers the
best set of tools available. These companies know that one way to
accomplish this goal is to empower customers to modify and
personalize their software to meet individual needs.
1
2 I Chapter 1: Introducing VBA I
We use the Project Manager to begin new VBA projects and open
existing VBA projects.
D~ oal ~"" : ·· 11
In this dialog box, click the Load Project button. Now, browse to the CD
included with this book for a folder named "MVBA Files': In this folder
4 I Chapter 1: Introducing VBA I
you will find a file named Introduction.mvba. Select this file and click
the OK button.
,.--------- ---
E!le Qjl'ectory
Files: Directories:
UDkQ.c!~.J!lyqiL_______ J D:\MVBA Files\
Inlroduction.mvba ~ ~D:\
~ MVBAFiles
This loads the .mvba file into MicroStation and displays it in the VBA
Project Manager.
Opening an MVBA file does not close the Project Manager. The Project
Manager remains open until you click the Close button in the upper
right-hand corner of the dialog box.
Now that we have loaded an .mvba file, we can run some code. How do
we do it? There are a few ways. Let's begin by running code from within
the VBA Project Manager. If the VBA Project Manager (VBAPM) is
closed, follow the instructions above to re-open it. Make sure to load the
Introduction.mvba file. In the VBAPM, select the VBA Project
Introduction.mvba. Now look at the top of the VBAPM for a triangle
that looks like the play button on a VCR. This is the Run Macro button.
I How Do We Use VBA? I 5
When you click it, the Macros dialog box opens, which allows you to
select which macro (procedure or function) you want to run .
. Run ~
Module1.PlocedureA
. Cancel .1
Module1.ProcedureC
Delete .wI
M~rosin; I<~II St~!1daL~'proie_c.t ~~.
, o· • f.:i
Select Pr ocedu r eA from the list of macros and click the Run button. The
macros dialog box closes and a diagonal line is drawn in the active
model. Proce dureA draws a line from (0,0,0) to (10, 10,0) in the active
file. If the macro is run and the line is not visible, use the Fit View button
to zoom the active view to display all of the contents of the file.
Remember, the steps to running an MVBA macro are:
1 Load the MVBA file using the VBAPM (VBA Project Manager).
2 Select the project in the list of projects.
3 Click the Run Macro button in the VBAPM, or click the
MicroStation menu Utilities> Macro> Macros, or hold down the
<ALT> key on your keyboard and press <F8> key.
It's a three-step process. Of course, if the .mvba file is already loaded,
You do not need to load it each time you run the macro. You can run a
specific macro by using one of three methods described above in Step 3.
You have just run a macro using the VBAPM. Now run one by using the
<ALT + F8> keyboard shortcut. Hold down the <ALT> key and then
press the <F8> key to display the Macros dialog box. Select Proced ureC
from the list and click the Run button. ProcedureC draws a square using
6 I Chapter 1: Introducing VBA I
lines from (0, 0, 0) to (10,0,0) to (10, 10,0) to (0, 10,0) and finally back
to (0, 0, 0).
That's all there is to running a MicroStation VBA macro. Load it and
run it.
Sub ProcedureA ()
' ********
'* This Procedure draws a line from (10.10.0) to (30.10.0)
'********
Dim Sta rtPoint As Point3 d
Dim EndPoint As Poin t3d
Dim MyLine As Lin eEle ment
Sta rtP oint.X = 0
St artP oint.Y = 0: StartPoint.Z = 0
EndPoint.X = 10: En dPo in t . Y = 10: EndPoint.Z 0
Set MyLine = CreateLineElement2(Nothing. _
Star tPoint. EndPoint)
ActiveModelReference.AddElement MyLine
End Sub
Some of the applications we write will have no GUI, but we will also
explore the visual side of Visual Basic.
REVIEW
VBA projects are contained in .mvba files. Each file contains code and
can also contain graphical user interfaces. Load and unload VBA
projects using the VBA Project Manager. After the code is written, You
run VBA projects and the code they contain by using the MicroStation
menu Utilities> Macro> Macros ... or by pressing <ALT +F8> on the
keyboard.
Learning VBA is very much like learning a new language. It requires
patience and time. Keep this in mind as we continue to study together.
8 I Chapter 1: Introducing VBA I
2 The VBA Project
Manager
You have already seen how to display the VBA Project Manager.
Remember, go to the MicroStation menu Utilities > Macro > Project
Manager. We used the Project Manager to load a VBA project and run a
couple of macros contained in that project. Let's take a more
comprehensive look at what the Project Manager can do for us.
[8 The Project Manager gives us the ability to load existing VBA
projects.
[8 The Project Manager allows us to run the procedures and
functions of projects that have already been loaded.
[8 Start new VBA projects using the Project Manager.
9
10 I Chapter 2: The VBA Project Manager I
We can use the MicroStation menu to display the VBA Project Manager
or we can hold down the <ALT> key and press the <F8> key to display
the macros that are loaded and are ready to be run.
We need to be careful when discussing the VBA Project Manager. The
term 'Project Manager' is so generic it could be confused with other
products or functionality. For brevity we will refer to the VBA Project
Manager as the VBAPM from time to time throughout this book.
Now that we have identified the VBAPM's functionality in general it is
time to examine it in greater detaiL
A Begin a New VBA You are prompted for the location of the new .MVBA file
Project and for its name.
B Open an Existing Select an existing .MVBA file to load into the current
VBA Project session.
( (lose VBA Project This button is enabled only when an existing project is
selected.
D Save Project As .. When an existing project is selected, you can save it to a
new location and/or a different file name.
E Display the VBA All saved VBA projects and new projects are edited from
Editor within the VBA Editor.
IVBA Project Manager Functionality I 11
F Run Macro Click th is butt on to d isp lay th e Run Macro dialog box
wh ere yo u se lect and execute specific macros.
G Record Macro Enabled when an existing project is selected. When
activated, activities in MicroStation are recorded to a
macro in the selected project.
H Stop Recording Enabled only when actively recording a macro. When
Macro stopped, the macro is placed in the selected VBA Project
under the name "Macr01'; "Macr02'; Macr03'; etc. The
Macro Recorder automatically names the macros. You
can rename recorded macros in the VBA Editor.
J Pause Record ing Pa uses the record ing of a macro and togg les between
Macro Pause / Resume Recording.
K Auto-Load Sets a specific VBA project to automatically load each
ti me Mi croStation is opened . When you click in the
column, a checkmark indi cates th e fil e is set t o Auto-
Load.
We have just identified ten things that you can do directly from within
the VBA Project Manager. One of these is "Run Macro" which, rather
than actually running a macro, displays the Macros dialog box.
12 I Chapter 2: The VBA Project Manager I
Mac[oname: Run I
lii'U.
ProcedureA I
ProcedureC
Step Into executes the macro in debug mode stepping through the code
one line at a time so we can see how the code is executing, what values
are stored in variables, etc. It is one of the best features of VBA, whether
you are a novice programmer or a seasoned developer.
The Edit button takes us into the VBA Editor window with the cursor
on the top line of the selected Macro.
The Delete button deletes the selected Macro from the VBA Project.
This is a very dangerous button. After all, there is no Undo button
displayed in this dialog box. Is there? Use with care.
Macros in: lists VBA projects. If you select <All Standard Projects>, the
Macro list displays all executable macros from all loaded VBA Projects.
Selecting a project filters the Macros list to display only those in the
selected project.
The Description area allows us to type in a description for a selected
macro. This is a nice feature because we are given the ability to provide
more information than by using the macro name only.
For example, we do not need to name a macro,
I Review I 13
REVIEW
The VBA Proj ect Manager is useful for perfo rming a number of tasks.
Among them are:
III To load and unload VBA projects (MVBA files) .
IB To save existing VBA projects to new files and locations.
III To begin new VBA projects.
IB To record macros into existing VBA projects.
III To use Auto-Load to automatically load VBA projects within
theVBAPM.
III To enter the VBA Editor from within the VBAPM.
14 I Chapter 2: The VBA Project Manager I
3 The VBA IDE
Open the VBA IDE PDQ!!! Yes, the IDE is WYSIWYG. GM?
Translation: Open the Visual Basic for Applications Integrated
Development Environment Pretty Darn Quick!!! Yes, the Integrated
Development Environment is "What You See Is What You Get". Got
Milk?
The VBA IDE is where we do our VBA programming work. As with
most Windows programs, the VBA IDE is composed of three elements:
[8 Menus
[8 Toolbars
[8 Windows
1S
16 I Chapter 3: The VBA IDE I
i E.ila gdit S!jew insert FQ.r(llat Q,ebug &un Iools 8dd·lns ~indow lielp
MENUS
Nearly all Microsoft Windows applications utilize Menus to issue
commands. Many menu items have shortcuts. For example, holding
down the <CTRL> key and pressing the <P> key does the same thing as
selecting File> Print from the menu. Whether you click your mouse or
use the associated shortcuts, it is helpful to know what a menu item
does. Let's look at the menu items that are available in VBA.
File Menu
w;]
[B Import File imports existing
l! import File ... Ctrl+M form (.frm), module (.bas), and
r;;Xport File .. , Ctrl+E class (.cls) files into our project.
Remove
gj E,rint .. , Ctrl+p
exports forms,
[B Export File
~Iose and Return to Micro5tation Alt+Q modules, and classes from our
project to their own .frm, .bas,
and .ds files. After these files have been exported, they can be
imported into another project.
[B Remove removes forms, modules, and classes from our project.
When we attempt to remove an element from our project we are
asked if we want to export it (save it) first.
I Menus I 17
Edit Menu
[B Undo and Redo are standard
~
Windows menu items. ;1 Can'l: Und" Ctrl+Z
,f,
ICan't Redo
':ut ,: ttl+X
standard Windows Clipboard I ~() ~opy Ctri+C
objects.
~l ::~:'~;ext ,:trl:
[B Select All selects all text when in a ,l R~DI~~8' " CtriHi
, i -,.--,-,---,--,--,-,,------,-,,---
Code window or all controls when t:~1 ~ndent Tab
View Menu
IB When looking at a user form ,
click Code to jump to the code
:rifI: ~ode F7
~ Qbject Browser F2
associated with the code we are
in' [mmediate Window Ctrl+G looking at.
~ Local~ Window
IB Click on Definition when the
&}' Watch Window
Insert Menu
[B Procedure displays the Add Procedure rnsert '--_ __
Format Menu
8!ign
Make Same Size
'X 'f· Size to Fi~
Size to Gri!J.
Use the Format menu to perform standard
tlorizontal Spacing ~
Ilertical Spacing
formatting when editing a User Form.
~enter in Form
Atr ange Buttons •
~. §.roup
!fl klngroup
Qrder
Debug Menu
Compile Default
The Debug menu allows us to c:;] Step into F8
Run Menu
IB Run Macro, Break into, and Reset
~ Run Macro F5 code execution by using these menu
UJ 8rea~ ctrl+8reak items in the Run menu.
la B.eset
III Design t10de IB Design Mode is a standard VBA
button that does nothing substantive in
the MicroStation implementation of VBA.
Tools Menu
IB References allows us to add a
reference to existing DLLs and type ~ B.eferences ...
ill ' additional Controls ...
libraries. For example, if we want to
t1acros ...
work with Microsoft Excel, we can add 'i - - - - --1
Qptions ...
a reference to the "Microsoft Excel t Def ault Prop~I'ties .. .
,
Object Library". Doing so makes ...; QJgital Signature...
Add-Ins Menu
Third party developers can create add-Ins for
VBA. Add-In Manager displays the Add-In
dialog box where we can set properties for
available add-ins.
I Menus I 21
Since we will not be discussing Add-Ins anywhere else in this book, here
is a snapshot of the m anager with an add-in that has been loaded. Add-
ins can be loaded based on the "Load Behavior" settings.
-··--------·-·---------:---·------------·!
Available Add-Ins ' Load Behavior , ' OK
r. VBA-Add l~f~;"~li';;'Stati~n X~r Stait~p 11];;r;,~ded-' I
Cancel
L -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ~: ~[ - tl-elp- - '
_____._____
.g,~sc lipti on . _ ________ _
Load Behavior ..-
Add-In created for MicroS tation VBA .A !
::.J ["oadcd/lJnio.,ded
CJ Lo~d on 5.1altup
.. ........-- .... ,)
Window Menu
~.Jiti9=
'H_.ll_ _ _--,
SQ.i,t These are the standard menu items
Tile tiorizontaliy available in nearly every Microsoft
Tile 'lerticaliy
Windows program.
hascade
~ 8,rrange Icons
Help Menu
!B We will cover Help issues in the
Help .'--_ _ _ _ _ _ _-,
next chapter. One way to get there ill-Microsoft Visual Basic tielp F1
is by clicking the Microsoft Visual J 8,bout Microsoft Visual Basic, , ,
Basic Help menu item.
TOOLBARS
Toolbars offer a very quick way to issue a command. One click is usually
all it takes to get things started. Compare this with at least two clicks to
issue the same command using a menu and we can instantly double our
CIP (Command Issuing Performance). As a general rule, all commands
issued by clicking on a toolbar icon can be issued from the menus.
It can take a little while to become familiar with toolbar icons. Until you
learn what each icon does, hold your cursor over an icon to see what the
icon does.
Standard toolbar
The Standard toolbar is very, very important. Why? Because the only
way to save the changes we are making in our VBA project from within
VBA is to click the Save button. We cannot Save changes by using the
menu. We must use the Save icon in the Standard toolbar. And please,
please, please, my friend, save your project often. There are few things
worse than spending a couple of hours working on a project only to have
something silly like a power outage or a fatal error cause you to lose all
of that work.
.~View MicroStation-1 Notice how holding your cursor over an icon displays the icon's tool tip .
~:'llI n l' ~
:- '@J i:.Ja '"
~
We could show each and every button on every toolbar but that would
be a bit of a waste because you can move your cursor over the icons to
see what they do.
Edit toolbar
The Edit toolbar displays
functionality found in the ~i~,,-~~,"~ili~~1:!1I; ~~J~A~"
Edit menu.
Debug toolbar
The Debug toolbar displays the functionality found in the Debug menu.
I Windows I 23
UserForm toolbar
The UserForm toolbar exposes
UserForm ... . ~ 0(: ,i." \ ~ ;"';,T X
"1 J:) ~ lfll I;'. • ~ • ca . lfioii~;~ ·----··:':] functionality found in the Format
menu.
WINDOWS
Use the toolbars and menu items to display and hide VBA windows.
Let's take a look at the VBA windows we will be working with on a
regular basis.
Project Explorer
The Project Explorer displays the top-level
objects in the loaded projects.
Forms In this project we have a form named
L... EID UserForm!
8"es Modules UserForm 1, a module named Module 1 and
: \.. ~ Module!
a. @j Class Modules a class module named Class 1. The view
'. '@I m!D1 shown uses folders to group the common
types of objects.
Object Browser
Classes
(; <g lobals>
@J Ac cuDrawHints ActiveDes ignFil e
@J ACSManager ActiveMode lReference
@J Application
@J ApplicationElement ActiveWorkspace
@J App licationObjectCo AddAttachmentEventsHand ler
@J Arc Element AddChangeTrackEventsHandler
@J AreaPattern AddLevel ChangeEventsHandler
@J Atta chment AddModalDialogEventsHandler
@J Attachments AddMode lActivateEventsHandler
Properties Window
Watch Window
UserForm1.Cornrnand8utton1_Click
DesignFileJDesignFile UserFonn1.Cornrnand8utton1_Click
ModelReferenceilvlodelReference UserForrn1 .Cornrnand811tton1_Click
Settings,Settings UserForm1.Cornrnand811tton1 _Click
ActiveWorkspace WorkspaceNVorkspace UserForrn1 .Cornrnand8utton·I _Click
AttachedCeliLibr6 <No cell libra Cell Library UserForrnl .Cornrnand8utton1_Click
8spline,8spline UserForrn1 .Cornrnand8utton1_Click
CadlnplllGlIelieiCadlnplrtGlIeue UserForm1 .Cornrnand8utton1 _Click
"graph paper Siring UserForm1 .Cornrnand8utton1_Click
CornrnandStatelCornmandSiate UserFonn1 .ComrnancI8utton1_Click
Long UserForm1.Cormnand8utton1_Click
CursorlnforrnationiCursorlnformati UserForrn1 .Cornrnand811tton1 _C lick
ObjectN8Project UserForrn1.Cornrnand811tton1 _Click
FuliNarne "C:'Prograrn I String UserForrn1 .Cornrnand8utton1 _Click
HasActiveDesign True 800lean UserFonn1.Cornmand8utton1_Click
H asAct iveMode l~ True 800lean UserForrn1 .Corn rnand8utton1_Click
Height 1201 Long UserForrn1.Cornrnand8utton1_Click
IsAcadernicVersi, False 800lean UserForrn1 .Cornmand8utton1_Click
IsCeliLibraryil.ttac False 800lean UserFonn1.Command8utton1 I
Locals Window
DesignFilelOesignFile
ModelReferencelModelRefen
SettingslSettings
WorkspaceNVorkspace
«No cell library> CeliLibrary
Bsplinefaspline
CadlnputQueuelCadlnputQue
"chapjer03.dgn (2D - va Dor string
CommandstaielCommandstal
CurrentOraphicOroup 1 Long
CursorlnformaiionlCursorlnfo
The Locals window looks a lot like the Watch window. There is one
primary difference however. To look at items in the Watch window, you
must add a watch to the item. The Locals window automatically displays
the variables declared in the active procedure or function along with
each variable's type and value.
Immediate Window
The Immediate window does a couple of things for us. First, it allows us
to display text as our code executes. When we use the following code
Dim MyApp As Application
Set MyApp = Application
Debug.Print MyA pp.Capt ion
the caption of the MicroStation application is printed to the Immediate
window. For this reason, it is also called the Debug window.
The other thing the Immediate window does is it allows us to execute
code immediately. For example, we can type
MsgBox "Learning MicroStation VBA "
I Windows I 27
in the Immediate window and press the <Enter> key. When we do so, a
Learning ~1icroStation VBA
MessageBox displays.
Toolbox Window
The Toolbox window displays the standard
controls that can be placed on our user 1
Controls
forms. It only displays when a user form is ~ Aabl~1ffiI
the active window in VBA. If we are working P(o';::!L1-l
with a user form and the toolbox is not ..!..l:..:J ~.!l~
visible, click on the Toolbox icon in the
Standard toolbar or go to the View >
Toolbox menu to display it.
All of the windows discussed so far are dockable except for the Toolbox.
This means they can be snapped to the bottom, top, right, or left
window of the VBA IDE. These windows' dockable property is set in the
28 I Chapter 3: The VBA IDE I
Docking tab of the Options dialog box. To view this, go to the Tools
menu in VBA and select Options.
I ~ii~iii:~~i~t.i.Wi6~9.0.:
I ~ L.ocals Window
I ~ ~atch Window i
Ii ~ !:.roject Explorer
I ~ Ptoperties Window
I ~ Qbject Browser
-.- -:,', :.
r - OK-- I ( ."
C~ncel I[ _ Help
Other Windows
There are a couple of additional windows in VBA we should discuss. As
we have already discovered, VBA projects are composed of forms,
modules, and classes. Each of these elements has its own windows.
...
. ... .
. . . ... . .
..... . . ., .. . .. . . • .
- . ... . . . . . . . . .. . , ... ... . , . .. . . .
, '-
.
.... . . . . ., . .
. . . ,. . .. ..
... . , . . . . .. .. . . . . ..... ., .. .... ..
. ... . . . . . .
.... , ...
I Windows I 29
REVIEW
The VBA IDE (Visual Basic for Applications Integrated Development
Environment) is where we do our programming, i.e. writing code and
creating user interfaces. As you become more familiar with this
environment, you will be able to develop your programs much more
quickly.
4 Finding Help
Finding help can be one of the most difficult aspects of learning a new
programming language. Why? If you have a question for someone, you
can converse with them until the question is clear. That's easy. When
learning VBA, however, you don't always know what to ask. For example
you might ask, "How do I put something on a form that forces a user to
enter a numeric value?" If you could ask a VBA guru this question, you
will get a straightforward answer. Working through a Help file for the
answer is different. For starters, even if you know what to ask but you
don't know the correct terminology, you won't find the answer.
Distressing? Yes. Frustrating? Definitely. The end of civilization as we
know it? No.
This book is targeted toward helping you learn MicroStation VBA. It is
filled with code samples and explanations but it does not contain every
answer to every possible question. Here a few things that will provide
help when you need it.
In this chapter:
[B Terminology
[B Help Files
[B The Net
[B The Object Browser
31
32 I Chapter 4: Finding Help I
TERMINOLOGY
Thingy. Dilly Whopper. Whatchamacallit. Gizmo. Whether we are
asking a person or a computer, these words will get us nowhere. How
can we get a little closer to the right keyword?
Let's begin by looking in VBA.
--- ---~ - ---- --- - - - - Holding your cursor
-- --- ---
ToolboH ®
over a variety of objects
Controls I ' ,
displays a Tool Tip.
r ~- A abl ~~ P" r.: ;: L1:-'...!.l~:;%JQI
" , There is a ComboBox
ComboBox icon in the Toolbox. If
we ask about a
Combo Box we are
more likely to find answers than if we ask about a DropDown. Both
combinations of words may make sense to us, but using the correct
name for the control gets us closer to finding answers to our questions
than using terminology that, although descriptive, is not correct.
Since the terminology used in VBA may be foreign to you when getting
started, it is a good idea to make notes or highlight areas of this book
and other resources when you come across a word or phrase you want to
remember or that you may want to be able to find quickly at a later date.
For example, if you are asked to provide a string, you may produce a
piece of flexible material useful for restricting blood circulation in one's
index finger with the intent of reminding you of something. As for me,
I'm just as likely to forget the string is tied around my finger as I am to
forget why the string is there in the first place. What does this mean?
Before long we are collectively fingedess. Or is it finger-free? Digitless?
ITerminology I 33
HELP FILES
One way to display the VBA Help File is to go to the Help menu in VBA
and select Microsoft Visual Basic Help.
1il
-~---------'-----",---'----------------:""'I: I
ttl.
~ • Visual Basic Conceptual Topics
We lcome to the Visua l Basic documentation.
tt ll .•
Visual Basic How·To Topics
Visual Basic Language Reference Visual Bas ic in cludes ma ny docume ntatio n too ls, , . !I'
Visual Basic Add·ln Model each designed to he lp you learn and use a
particular aspect of the product. The documentation
~ • Microsoft Forms Reference provided with Visua l Bas ic includes the following:
• Visual Basic User Interface He lp
Look he re for He lp on interface el ements of the
Visu al Basi c Editor, such as command s, dial og
boxes, win dows , and toolbars.
I • Visual Basic Conceptual Topi cs
The Conceptual Help top ics include informatio n
I to help you understa nd Vi sual Bas ic
programming .
I
.' • Visual Basic How-To Top ics
Look in the Ho w To section of He lp to find usefu l
common pro cedures, for examp le, how to use
the Object Browser or ho w t o set Visua l Basic .
Environme nt options.
• Vi sua l Basic Lang uage Reference
The Lan guage Reference is t he pl ace to fi nd
He lp on Visua l Bas ic the lang uage : all its
methods , properties , stateme nts , functio ns ,
op erato rs, and objects . fal
It is filled with a large amount of information but also gives us the ability
to organize our own unique help file by using of the Favorites tab.
So, you want a little help with a ComboBox? Let's begin in the Contents
tab and drill down to the ComboBox starting with the Microsoft Forms
Reference.
I Help Files I 35
Contents tab
'ml [iJ
().,
if {l, <? s> ., [1J ~ Jt. ~
Hide Locate Pr>;:·.j!Cri.;~ N'::-i!t Back Forward Stop Refresh Home Font Print
It may take a little digging to find what you are looking for using the
Contents tab but knowing the correct terminology is a big help. At the
top of many help topics, are links for "See Also;' "Example;' "Properties;'
"Methods;' "Events;' and "Specifics". If you are looking for more
explanations, "See Also" is very helpful. If you are looking for code to
copy and paste, "Example" is the link you want. For information about
specific Properties, Methods, and Events, click the appropriate link.
The body of help topics often contain hyperlinks to other topics and
pop-ups to explain the highlighted text in greater detail.
You can print help Help topics by clicking the Print icon at the top of the
file.
36 I Chapter 4: Finding Help I
Index tab
Contents !;;ontents [ Index · l l iarch I~
Type in the key~ord to find:
Iistring [Itext
CompareMode property
~!
clearing
Filter function color
InStrRev function comparing
Replace function converting
Split function culling and pasting
wildcards entering
string conversion from numbers
String data type importing
String function looping
String keyword searching/replacing
String$ function 5 tring data type
strings text files
aligning inserting
character TextStream obiect
comparing The binary compatibility DLL or E>
concatenating The binary compatibility DLL or E>
converting Then keyword
data types This (Me keyword)
fixed-length Tile Horizontally command
formats Tile Vertically command
iustifying Time function
leftmost characters time intervals
length adding
manipulating difference
matching Time keyword
middle characters time stamp
removing spaces Time statement
repeating Time$ function
replacing Timer function
returning from functions timer s
reversing times
rightmost characters adding
searching converting
spaces creating
substrings Date data type
variable-length determining
Display Display
The Index tab displays a different way to organize help topics. It works
much like the index of a book. This is another area where using correct
terminology is very helpful. If you enter "string" in the keyword textbox,
you get a large number of linked topics. Enter "text" and you get a
number of unrelated topics (if we are looking for information on the
String variable type) but also a link to the "String data type:' So even if
you don't have the exact terminology, getting close to the correct word
may link you to the correct topic.
I Help Files I 37
Favorites tab
Tallies:
m &W data in a ListBox or
~~ifil; •
S to
,
See Also
In a ListBoK or (1I'ttfijifi]:litft with a single co lu mn,
the AddItem method provides an effective
technique for adding an individual entrr,no the list.
In a multico lumn listBo H or (1tttjj1ifi1: I I howe ver,
the List and Co lum n properties affer another
techn ique; you can load the li st from a two-
I"
dimensional array.
If you find a particularly helpful help topic or one that was difficult to
find, add it to your Favorites. The "Current topic" text box displays the
38 I Chapter 4: Findin g Help I
default topic title. Fortunately, you can change this description to
whatever you want it to say. For example, you could change it to
"ComboBox - Adding To the List:' Then click the Add button.
Favorites is one of the best ways to personalize the standard Visual Basic
Help file. Sure, you can print out page after page after page, use a
highlighter and make a binder. That is a fine way to catalog what you
have learned and create additional reference material. But Favorites is a
quick way to find 'bookmarked' topics and jumps to linked topics. It also
keeps the Copy and Paste functionality available.
To sum up, VBA stands for Visual Basic for Applications. Thus far in
this chapter, we have been discussing how to find help for the "VB"
portion ofVBA. What about the ''!\'? The Application? Good question.
Learning everything about the VBA programming language will give us
some good background but will not get us very far when attempting to
interact with MicroStation.
I Help Fi les I 39
One of the most helpful sections in the MicroStation VBA help file is the
Examples folder, which contains excellent explanations as well as the
code to perform specific tasks.
40 I Cha pter 4: Find ing He lp I
Another excellent way to open the MicroStation VBA Help file is to
select a MicroStation-specific API call in the Object Browser or in our
code and hit the <Fl> key on the keyboard.
THE NET
Got Net? http://msdn.microsoft.com/isv/ technology/ vba/default.aspx
gets us to Microsoft's VBA web site. If this URL is difficult to remember,
you can also use http://msdn.microsoft.com/vba, which contains links
to white papers, Knowledge Base articles, and other reference materials
that comprise a wealth of information on VBA programming and its
associated topics. Although you are not likely to find much about
MicroStation's VBA-specific implementation here, you will find many
other examples on how to accomplish specific tasks m the VBA
environment.
GIi! VI\lIoI Uatl < rur epllliNti!i'tl 6 a hpl"",,, 'iRA PArt tW: prp9 r.!1'!!
)'OUfS itud ~lJl,ItU"J i.M1"",,,,. b~"fdl, "'llJ l!Iot.~~m.Rt... qJ' W~ rOl,lli~A1. V&~. YQllll4<lqI"tt.to!~II., ~~ ..
lotl.ay! V.eA 4,'. Ml!!rn~t (I t tf'J. Hit;I'on¢!t \1ft:. J"4'tto.e, 'I*~"T' . a..,.."
..bl)t.It ~Qotn. Qf th. tlf"',,,h.t( l(>lfU <I"t .u. it P.i, th~"' .
j)tIt'J:J!!\.XQMIlU.Y..lJI.~,IL'U .Q
tn~1~IlI'\O tNJ VilA ~O)( wn
ONbl" »11 \1) l).... lIl\)J);tt 1$1~ Lt~.U».I!I.Q..,eArtntli
Mnef(.'f ~ Wlt~ol,,~b/l;(I \I'M intc ynlOl ~DII~~tll\. See ttI~ ~mp.tlnI1;1 'Nhleh l!IilVtl; hetf\,« vaA ~d tN
pr(llflJtt~
111". b\lV4 VQA ' f'".)!JIIt(lo
Google, Yahoo, and other search engines can unlock the rest of the
Internet's VBA knowledge for us. Remember, there are a lot of
programming languages out there. A search for "Message Box" returns
us a large number of web pages to check out, but in addition to VBA
results, we will get pages for C#, C++, Java, JavaScript, Fortran, Pascal,
and other languages.
A quick trip to the Bentley web site and a search for "vba" nets some
good information as well. Why not go directly to the source?
Search
19 lOO,:) Ben'tiey Systems, Incotpora w.d Ptl'J<lCY I Tem15 of U.H~ I W-ehmaster 1 1.800.SF.NT1.EY
~BENfLEY
NicroStation
Bentley ,rnicrostation .'18 .xme.3rlyacce$$ (new)
displays its properties, metho ds, and events m the listbox on the right
side of the window.
- - -
Object Browser , ' , ~
tMicroSt .lt·i~·~~·DG·'I-···'-···-· · .........;.. j
'---------' vI '" ~
Cla sse s Members of'Application '
Gl <global s> " : I1i' ACSManage r
li!'J AccuDrawHin ts _ 11i'
li!'J ACSManager ActiveMode lReference I1i'
li!'J 'Appiication- ActiveSettings I1i'
~ 'APpiicaiionElemeni' ActiveWo rkspace I1i'
~ Appli cation Objec tConnec tor .,~ AddAttachm entEventsHandl er
ti:I Arc Element "~ AddChangeTrackEve ntsHand ler
ti:I AreaP attern " ~ AddLeve lChangeEventsHand ler
~ Attac hmen t "'~ Ad dMod alDialogEventsHandler
~ Attac hments ;~ Add Mo delAclivate Eve ntsHa ndler
li!'J Auxili aryCoo rdinateSystemE lemer .,~ Ad dMo delChang eEventsHand ler
~ 8s plin e ,~ Add SaveAsEventsHa ndle r
li!'J 8s piin eCurve .. "~ Ad dViewUpdateEve ntsHa ndler
~ 8 sp iineCurveElement ,.~ Appen dXDatum
ti:I 8spiineSurfa ce ."~ ApplyHorizonta lScalingFixForEMF
ffl R c: n li n p !=:l l tf~ (' p l= lpmpn t v ~ .o:.~ AnnhMprti (';:. I~(' ~l i nnj:" ivj:" nrI=MJ='
For example, if you have selected Application in the ListBox on the left
and want to do something with the active design file in MicroStation,
click on ActiveDesignFile in the right-hand ListBox. The description at
the bottom of the Object Browser tells us the ActiveDesignFile property
of the Application Object returns a DesignFile object. We can now select
DesignFile in the Classes list (the listbox on the left) to see the Design
File's properties, methods, and events in the Members list on the right.
•, ~ .~ v
,.......".:.".....,..".....,........- _ ,.._v...•., ,..
.........................................
:::
REVIEW
Finding help is not always easy. Knowing where to look is the first step.
Next, using correct terminology moves us along the path to finding the
answers to our questions. Learning to use tools, such as the Object
Browser, provides more answers.
Keep in mind that the most simple subjects still require effort to learn
and retain. VBA is no different. If you allow yourself to become
frustrated, the chances of success are diminished. You can learn
MicroStation VBA. You really can.
5 Modules, Forms, and
Class Modules
In this chapter:
[B Modules
[B Forms
[B Classes
[B Procedures and Functions
MODULES
Code modules are the foundation of every VBA project. We use them to
declare variables that can be used from within the code module, by
other code modules, by forms, and even by class modules. Windows API
functions are declared in modules so the API calls can be used in our
project (more on Windows API functions later in the book). Procedures
and functions inside modules can be run from the VBA Project
45
46 I Chapter 5: Modules, Forms, and Class Modules I
Manager. In fact, code modules are so essential that an initial code
module is created every time a new VBA project is created. Procedures
written in code modules are the starting point for running code and
displaying forms.
Enough talking. Let's write some code.
Let's begin by creating a new VBA project named Chapter 05. Save it in
the folder C:\MicroStation VBA. After this new project is created, you can
see that a code module named "Module 1" is created automatically.
Rename this module modChOS.
Continue by creating a new procedure named Ma in. Inside the code
module, type
Sub Main()
When you press the
<Enter> key after typing
the above code, VBA
finishes the new procedure
by entering an "Exit Sub"
for us. At this point, the
module should look like
this:
The next thing we are going to do is enter some code in our new
procedure "Main:'
Sub Main ()
' Declare Variables
Dim MyLine As LineElement
Dim MyCir As EllipseElement
Dim CenPt As Point3d
Dim LineSt As Point3d
Dim LineEn As Point3d
Dim RotMatrix As Matrix3d
' Create Hor iz ontal Line
LirieSt . X = -1
LineEn.X = 1
Set MyLine = Application . CreateLineElement2(Nothing. LineSt. LineEn)
Application.ActiveModelReference.AddElement MyLine
' Create Vertical Line
LineSt . X = 0 : LineSt . Y = 1
I Modules I 47
Li ne En . X = 0 : Li neEn . Y = -1
Set MyLine = Appl i cation . CreateLineElement2(Nothing , LineSt, LineEnl
App1 i cation.ActiveMode l Reference . AddElement MYLire
' Creat e Ci rc l es
Se t MyCir = Appli ca t ion . Cr eat e El l ip se Ele ment 2(Noth i rg, _
CenPt, 0.25, 0.25, RotMatrix )
Application.ActiveModelReference.AddElement MyCir
Set MyCir = Application . CreateEllipseElement2(Nothing, _
CenPt, 0.5, 0.5, RotMatrix)
App l ication.ActiveM odelReference.AddElement MyCir
End Sub
The code above may look like a whole lot of gibberish at this point, but it
will make much more sense as we continue to learn VBA together.
Notice the comments inserted into the code. Remember, comments
begin with an apostrophe C).
Running this code draws two circles
and two lines in MicroStation that
create a target shape that looks like this:
The code works great. From now on,
any time we need to draw a target with
these dimensions centered at (0, 0, 0)
we have the code to do it. In mere
. I
milliseconds, we can draw this target by :I
running the macro Ma in whenever we
wish.
If we need to draw the target centered at (4, 5, 0) we can copy and paste
the code, and rename the procedure to Ma i n2. And then we can create
The more
Ma i n3 with different coordinates, then Ma i n4, then Ma i n5 and so on.
hard-coding
we do, the less
Right? Well, we could do that but there is a better way.
often we will Let's change the way we are doing things a little bit. Instead of having
be able to run
our macros.
Ma in draw a target at (0, 0, 0), we create a new procedure that draws the
target at the X, Y, and Z coordinates we specify. We will do this by
creating parameters for the new procedure.
Sub Ma in ( )
' Draw Targets
Draw Target 0, 0,
DrawTarget 3, 0, °
DrawTarget - 3, 0 , °
DrawTarget 0 , 3, °
Dr awTarget 0 , - 3 , °
End Sub °
Our procedure Mai n now draws five targets. More flexible? More
powerful? Absolutely. But the coordinates are still hard-coded. This m ay
work at times when we are setting up a page that is to be printed in
MicroStation. But how can we let the user specify the coordinates? Let's
expand our program a little by introducing a graphical user interface.
FORMS
User forms provide a graphical user interface
(GUI) for our users. We begin by inserting a
new User Form.
This form has three abels, three text boxes and
a command button. We will keep the default
names for each of these form elements except
for the text boxes. We want to rename the text
boxes to txtX, txtY, and txtZ. This is done in the
properties window inside VBA.
When a control is selected, we can make
changes to the control's properties in the properties window. As with
other windows in VBA, if the properties window is not displayed, show
it by going to the menu in VBA, View > Properties Window. After
changing the names of the text boxes, change the caption properties of
the labels and the command button to reflect the image shown above.
After you modify the properties of the controls on the form, change the
name of the user form to "frmChOS".
We are going to enter some coordinates in the text boxes. When the user
clicks the "Place Target" button, we want to use the entered coordinates
and use the OrawTarge t procedure we just created. We need to write
some code in the C1 i ck Event of the CommandButton. Double-click on
50 I Chapter 5: Mod ules, Forms, and Class Mod ul es I
the button when we are designing in our project to be taken into the
We can also eli ck Event of the CommandButton.
get here by
right-clicking
on the button
and selecting
View Code in CDbl(txtY . Text), CDbl(txtZ.Text)
the pop-up
menu.
You only need to enter one line of code to use both the DrawTarget
procedure and the values entered into the form's text boxes.
We are almost finished with this little project. We have a procedure that
draws targets. We have a form that allows users to enter coordinates. We
now need to give the user a way to display the form. We don't want the
user to enter the VBA environment to run this program, so we will make
another change to the procedure named Ma i n.
Sub Main ()
' Di splay the Form
fr mCh05 . s how
End Sub
Save your VBA program now. It would be a shame to lose this work.
Click on the Save button in VBA.
Saved? Good. Now run your program and see how well it works. From
within MicroStation, hold down the <ALT> key and press the <F8> key
on the keyboard.
I Forms I S1
button. Edit
The form is
displayed so we can Delete
enter numbers for X, Macros in:
[----------------::::1
<All Standard Projects> v,
CLASSES
You may know that we use classes to create objects, but did you know
that by putting a little thought into creating class modules, they can be
useful for years to come. How so?
In our current project, we can draw a target at any coordinate we specify.
That's pretty powerful and it meets our needs today. What happens,
however, if a year from now we find we want to change the target's size?
The procedure 0raw Tar get only allows entry of three parameters (X, Y,
and Z). We could modify the procedure to require four parameters, the
last one specifying the size. But this could break parts of our code that
are only providing three parameters. We could also make the new
parameter optional, but there is a better way.
We can create a new class that has X, Y, and Z properties. It will also
have a Draw method. When this is in place, we will add a Scale property.
We could add a Level property, a Color property, a NumberOfCircles
property, etc. We can add these properties today, tomorrow, or next year.
It doesn't matter when we add them. We just need to make sure that
when we add them we do so in a way that allows the previous code using
the class to continue to work properly without modification.
Time to write some code.
Let's add a new class module to our project. Do this by using the VBA
menu Insert > Class Module. Name it clsTarget (using the Properties
Window for this). It will have three properties and one method. The
most basic way to implement properties for classes is to declare variables
as Public in the General Declarations area of the class module.
Implement methods by creating procedures in the class module.
Begin by defining the properties.
Pu bl i c X As Double
Pub l ic Y As Double
Publ ic Z As Double
I Classes I S3
Next implement the Draw method. Recall that you can get this finished
project on the CD that accompanies this book and open it instead of
typing in all of the code. The Draw method was created by copying and
pasting DrawTarget and changing 'CenX' to 'X', 'CenY' to 'Y', and 'CenZ'
to 'z' to use the X, Y, and Z properties defined in the class module.
To make sure we are all on the same page, look at the screen shot of the
finished class.
'Declare Variables
Dim My L i ne As L ineElement
Di m Mye i r As El l ipseE l ement
Dim CenPt As Point3d
Dim LineSt As Point3d
Dim LineEn As Point3d
Dim RotMatrix As Matrix3d
'C reate Hori~ontal Line
LineSt.X =X- 1
LineSt.Y;::: Y
LineSt.Z '" Z
LineEn.X a X + 1
LineEn.Y = Y
LineEn.Z = Z
Set MyL ine = App 1 ieat ion. CreateL ineE lement2 (Nothing, L ineSt, L ineEn)
App l icatlon.ActiveHodelReference,AddElement MyLine
'C["eat.E: Vert-ieEll Line
LineSt.X "" X
LineSt.Y = Y + 1
LineSt.Z = Z
LineEn.X = X
LineEn . Y = Y - 1
LineEn . Z:c Z
Set HyL ine = App 1 ieat ion. CreateL ineElement2 (Nothing I LineSt I L ineEn)
Application,ActiveHodelReference , AddElement HyLine
'Create Circles
CenPt.X = X
CenPt . Y = Y
Ce nPt. Z :a Z
Set MyC i r = Application . CreateEllipseElement2(Nothing. CenPt. 0 . 25. 0 . 25. RotMatrix)
App l i c ation . Act ive l·lode lRefer e nce . AddElement MyC i r
Set MyC i r = App li cation . Cr eat e El l i pse Element2(Noching. CenPt, 0.5, 0.5, RotHatrix)
Appl i cation , Act i veMode lReference , AddEl ement HyClr
End Sub
Public X As Double
Public Y As Double
Public Z As Double
Sub DrawCi rc l e ()
' Dec l are Var i ables
Di m MyCir As Ell ipseE l ement
Dim CenPt As Po i nt3d
Dim RotMatr i x As Matrix3d
' Create Circle
CenPt . X 0
CenPt. Y 0
CenPt . Z 0
Set MyCir = Application.CreateEllipseElement2(Nothing, CenPt , _
0 . 25 , 0 . 25 , RotMatrix)
Application . ActiveModelReference.AddE l ement MyCir
End Sub
S6 I Chapter 5: Modules, Forms, and Class Modules I
DrawCi rc 1e draws a circle at (0, 0, 0) with a radius of 0.25. It can be run
by itself without the any other procedure or function.
Ora wC ire 1e3 requires us to provide X, Y, and Z values and gives the
option of providing a radius. If we supply a radius, it uses the value we
give it. If we do not provide the radius, it used a value of 1.25.
Here is one way to test our procedure DrawCi rcl e3:
Sub TestDrawCircle3 ()
DrawCircle3 2.25, 2.25, 0
DrawCircle3 2.25, 2.25, 0, 1.125
End Sub
The first time we call DrawCi rc l e3 we do not provide the optional
parameter. The second time we call it we provide a radius value of 1.125.
The first circle will be drawn with a radius of 1.25 (the default value) and
the second will be drawn with a radius of 1.125.
Sub TestDrawCircle3 ()
Once an DrawCirc le3 2 .25, 2 . 2 5, 0
Optional DrawC ircl e 3 2 . 2 5, 2 . 25, 0, 1.1 25
Parameter is DrawCi rcle3(X As Double. Y As Double, Z As Double, [Radil/s As DOl/ble= 1.25]) I
End Sub
declared in
the
Procedure, As we call functions and procedures, VBA displays a tip that shows us
any the parameters for the function or procedure that we are calling. Notice
parameters how the radius parameter is enclosed in square brackets. The square
after it must
also be brackets tell us that "Radius" is an optional parameter. We are also
optional. shown the value of the optional parameter that will be used if we do not
supply a value.
Another type of parameter that can be declared in a procedure or
function is called ParamArray. A ParamArray must be the last
parameter declared, because when we supply a value or values to the
parameter in code, we can supply any number of values for the
parameter. Here is an example of how it is declared and used in code:
Sub TestDrawCircle4 ()
DrawC i rcle4 1. 1, 0 , 0 . 25 , 0 .5, 0 . 75, 1. 1.25 , 1. 5
En d Sub
We provide an X of 1, a Y of 1, and a Z of O. Then we begin providing
radius values. After the code is run, we have six new circles in our
MicroStation design file.
Here are the six circles created by
Te st DrawCi rcl e4 .
We have created over 100 lines of code so
far in this chapter. The current module
now has nine different procedures in it.
Five of them can be run by themselves,
the others must be called by other
procedures or functions .
Speaking of functions, let's examine them in detail.
Function Pi () As Dou bl e
Pi = Atn ( l) * 4
En d Function
Here is a function named Pi . It does not accept any parameters and the
type of value it returns is a Double.
We specify what value is to be returned by assigning the return value to
the name of the function.
I Procedures and Functions I 59
This function, Pi, can be used now wherever we need the value of Pi.
The procedure DrawCi rc 1e3 allows us to provide the radius of the circle
to be drawn. But what do we do if we only know the area of the circle we
want drawn? We can calculate the radius if we know the area but we
need the value of Pi to do so. Rather than hard-coding a value of
"3.14159" for Pi, we can use the Pi function we just created.
Sub TestPi ()
Dim Circ leArea As Double
Dim CircleRadius As Double
CircleArea = 3 . 5
CircleRadius = Sqr(CircleArea / Pi)
DrawCircle3 2.5, 2.5, 0, CircleRadius
End Sub
We calculate the radius of the circle based on a given area. We then use
that value in the radius parameter of the procedure DrawC i rcl e3 .
The function Pi we just created does not have any parameters. It does
not need them because the calculation is always the same. Let's look at a
few additional functions that come in handy from time to time. They are
named RTD (Radians To Degrees) and DTR (Degrees To Radians).
Here is the arc created by the above code. It begins at 45 degrees and has
a sweep of 90 degrees.
Returning an Array
Functions return a value, right? Yes. But functions can actually return
more than one value through the use of an array.
As we will discuss more in the next chapter, but for now know that an
array is a variable that contains more than one value and that we can
return an array in a function. Here's what it looks like:
The Pol arPoi nt function allows us to define a starting point (X, Y, and
Z), an angle, and a distance. In return, we are given the resulting X, Y,
and Z elements of the coordinate as an array.
We return an array by declaring the return type of the function as a
variant. As we will learn in the discussion on variables, a variant can
hold any type of value, object, or array of values or objects. We declare
an array of doubles within the function and then we assign the array
variable to the function name. Here's one way to test the PolarPoint
function.
Sub TestPolarPoint ()
Dim StartCen As Point3d
Dim CenPt As Point3d
Dim RotMatrix As Matrix3d
Dim X As Variant
StartCen.X 2
StartCen.Y = 2
StartCen . Z = 0
Set MyCir = Application.CreateEllipseElement2(Nothing . _
StartCen . 1. 1. RotMatrix)
Application . ActiveModelReference . AddElement MyCir
Dim RotAngle As Double
For RotAngle = 0 To 360 Step 30
X = PolarPoint(StartCen.X. StartCen.Y. StartCen . Z. _
DTR(RotAngle). 4)
CenPt.X X(O)
CenPt.Y = X(l)
CenPt.Z = X(2)
Set MyCir = Application.CreateEllipseElement2(Nothing. _
CenPt . 1. 1. RotMatrix)
Application . ActiveModelReference.AddElement MyCir
Next RotAngle
End Sub
62 I Chapter 5: Modules, Forms, and Class Modules I
What do we get when we run Testpo 1arPoi nt?
Returning 'Types'
Thus far we have written functions that return either a single value or an
array of values. You can also return types. MicroStation VBA has a
'Point3d' type with three properties: X, Y, and Z. Let's copy and paste the
Polar Point function and make use of this type.
Sub TestPolarPoint2 ()
Dim Sta r tCen As Po i nt3d
Di m CenPt As Poi nt3d
Di m Rot Matr i x As Matr i x3d
Dim X As Varian t
StartCen.X = 2
I Procedures and Functions I 63
StartCen . Y = 2
StartCen . Z = 0
Set MyC i r = App i cation.CreateEllipseElement2(Nothing, _
StartCer.,1. 1. RotMatrix)
Applicatior . ActiveModelReference . AddElement MyCir
Dim RotAngle As Double
For RotA~g l e = 0 To 360 Step 30
Cen Pt = PolarPoi nt2 ( Sta r t Cen . X, St ar t Ce n . Y, StartC en . Z, _
DT R(Rot Angl e ) , 4 )
Set MyC i r = App l ication . Create E llipse E lement2(Nothi~g, _
CenPt , 1 , 1, Rot Matrix)
Application . Act i veModelReference . AddE l ement MyCir
Next RotAngle
End Sub
Returning Objects
One additional return type is worth mentioning. In addition to
returning values and types, a function can return objects. Here is one
example.
Ge tThr eeV a1s changes the values of the parameters that are passed in.
This can be a powerful feature if it is used correctly. It can also cause a
great deal of confusion if it is not understood. Suddenly, variables that
were holding one value could hold another value.
If we do not want a function or procedure to change the values of the
variables passed as parameters, there are a couple of ways we can do this.
The fi rst technique requires discipline on our part. The second
technique is a more definite method.
Declaring Variables
Variables are used extensively throughout our code. Variables are
declared with a name and a type. We will learn more about this in the
next chapter. What is important to understand now is that variables
have a scope. There is a pre-determined amount of time when a variable
can be used. The variable's scope depends on where it is declared and
what keywords (if any) are used when it is declared. There are two places
where variables can be declared. One place is inside the procedures and
functions in which they will be used. We have seen numerous examples
of this so far. The other place we declare variables is in the General
Declarations area of code modules, forms, and class modules.
UserForml . TestVariable = 4. 5
We can use th e variable TestVa ri ab le only by addressing it th rough th e
form an d the form m ust b e 'in scope' fo r this to work.
Modules - Publicly declared variables are in scope for all areas within
the sam e project.
Classes - Publicly declared variables are seen as read/write properties
for the class.
Option Explicit
By default, if we attempt to use a
variable that is not declared, it
inherits the type of 'Variant: We
can force ourselves to declare
variables by using "Option
Explicit" m the General
Declarations area of modules,
forms, and classes.
In this example, we have declared "Option
Explicit" in the General D eclarations area.
~ Compile error:
When we attempt to run the macro test shown I • Variable not defined
above we get an error.
r oK ·m )i [ Help
REVIEW
[B Write code as procedures, functions, or inside user form events.
1+N+3=7
What is N? N is a variable. In the above equation it represents a number.
If we were to solve for N we would get a value of 3.
"Learning MicroStation VBA " & N & " Easy:'
What is N? N is a variable. In the above
equation it represents a string of characters.
Learning MicroStation VBA 15 Easy,
What string of characters does it represent?
"IS".
In this chapter:
[B Standard VBA Variable Types
[B MicroStation-Specific Variable Types
[B Assigning Values and Setting Objects
[B Arrays
[B Constants
[B Variable Names
[B Option Explicit
[B Using Variables
69
70 I Chapter 6: Variables I
Dim N as I nteger
N= 7 - 3 - 1
Di m N As String
N = " I S"
MsgBox "L earning Mi croStation VBA " & N & " Easy ."
Here we declare N as a string. A string is a group of characters. After a
variable is assigned a value, you can use it in the place of a number, text,
or some other type of value or object.
We will use variables extensively throughout this book. Let's examine
some of the more common types of variables available to us.
Integer
Di m PageNumber as Integer
PageNumber = 2
We said that an integer is a whole number between -32,768 and 32,767.
If we need a variable to hold a value greater than or less than the range of
an integer, we must declare it as something different.
Long
Dim MySalary as Long
MySalaray = 123456
A long is a whole number between -2,147,483,648 and 2,147,483,647.
These numbers are much larger than those in the range of an integer. It
I Standard VBA Variable Types I 71
Double
Dim HoursToLearnVBA as Double
HoursToLearnVBA = 36 . 25
A double is also called a double precision flo ating point number. What
does that mean? It means the precision available for a double is twice the
precision available for single (also a variable type but not used as much)
and the decimal point can float to allow for greater precision of small
numbers or larger numbers with less precision. It is important to
understand the "floating point" portion of the description. If we expect
an extremely large number to be extremely accurate, we may not only be
disappointed but we could have less accurate results than we expected.
Consider this next macro, Var i ab l eTestC . It has a variable named N
declared as a double in which the numbers "1234567890123456789"
have the decimal in a different position each time with the last two
numbers shown are '46'. VBA rounds the '456' number to '46' because a
double variable is given a specific amount of memory in which to keep
its value. When we attempt to put more in it than it can handle, it rounds
the number to something it can hold.
Doubles can hold very precise numbers but as the value of the number
increases, the precision decreases. This is something to keep in the back
of your mind as you develop applications.
Boolean
Dim ICanLearnThis as Boolean
ICanLearnThis = True
A Boolean data type can hold one of two values: True or False.
Date
Dim XMRelease Dat e as Date
XMRe l easeD ate = " 5119/2006 8 : 00 : 00 AM"
String
Di m MyLevel Name as St r ing
MyLevelName = "utilElectricity"
A string data type contains text. Letters, numbers, and other characters
we on our computer keyboards can be held inside this variable. We have
seen that numeric variable types have ranges of values. This is because
their data types have a predefined amount of memory set aside for each
variable. Strings are no different. So how many characters can be held
inside a string variable? Approximately 2 billion (2,000,000,000). That is
a lot of characters.
Object
Di m MyExcelApp as Obje ct
Set My Ex c e 1APP = Get 0 bj e ct(. .. Ex c e 1 . APP1 i ca t i on " )
events. Others objects have their own unique properties, methods, and
events. When we declare a variable as an object, it is a generic object
without any previous knowledge of its properties, methods, or events.
Only after we set the variable to an object does it know what kind of an
object it is as well as its other attributes.
Variant
Di m PointArray as Variant
Variables declared as a variant can hold any type of value, point to any
type of object, or even contain an array of values.
Application
Dim MSApp As Appl i cat i on
Set MSApp = Application
OesignFile
Dim MyDGN As OesignFile
Se t MyDGN = Application.ActiveDesign File
ModelReference
Di m MyM odel As Mode l Refe r ence
Set MyM ode l = Ap pli cat i on . Ac tiv eMod el Refe rence
The ModelReference object is where the rubber meets the road. When
we draw inside a file, we do it through the ModelReference object.
When we want to find out what is in a file, we do it through the
ModelReference object. We will work extensively with this object
throughout this book.
Level
Di m My Level As Level
Set MyLevel = Application.ActiveDes i gnFile.Levels(l)
[B ElementLineWeight
[B IsActive
[B IsDisplayed
[B IsFrozen
[B IsLocked
[B Name
[B Number
[B Plot
LineElement
Di m MyLine As Li neElement
Set MyLine = App l icat i on . CreateLineElement2(Noth i ng .
Po i nt3dFromXYZ(0. O. 0) . Po i nt3dFromXYZ(4 . 5 . 6))
Appl i cation . Act i veMode l Refe r ence . AddE l ement My Li ne
EllipseElement
Di m MyC i rc l e As El l i pseElement
Dim Rot Matr i x As Matrix3d
Set MyCircle = CreateEllipseElement2(Nothing.
Point3dFromXYZ(0 . O. 0) . 1.5 . 1.5 . RotMatrix)
Application . ActiveMo delReference . AddE l ement MyCircle
Lines, circles, and arcs form the basis of much of the geometry found in
our MicroStation files. From MicroStation's perspective, circles are
essentially ellipses with equal major and minor radii. The code shown
above draws a circle centered at (0,0,0) with a radius of 1.5.
ArcElement
Dim MyArc As ArcElement
Dim RotMatrix As Matrix3d
Set MyArc = CreateArcElement2(Nothing .
Point3dFromXYZ ( O. O. 0). 1.75. 1.75. _
76 I Chapter 6: Variables I
RotMatrix, Radians(45 ) , Radia ns (90) )
App li cation.ActiveModelRefer ence . Add Element MyA r c
TextElement
Dim MyT ext As Text Eleme nt
Di m Rot Matr i x As Matr i x3d
Set MyText = Create Text Elementl{Nothing , "M icroStation VBA" , _
Point3d Fro mXY Z( O, 0 , 0), Ro t Ma t ri x)
Appl i ca ti on . ActiveModelReference . AddEl ement MyText
The TextElement object needs the text to display and a starting point.
When it is created we can set other properties such as the color, level,
and textstyle (which includes font, size, etc.) .
We use many more types of objects when programming MicroStation in
VBA and there is much more to learn about the objects we have just
introduced. They will be covered in greater detail as we continue to
learn MicroStation VBA.
Here we have tV'TO variables. One is declared as a string and the other as a
Level.
We assign a value to the LevelName variable by stating the variable by
name, using an equal sign, and then the value we want it to have. When
we use the Level object, we use the keyword 'Set' to set the variable to an
I Arrays I 77
ARRAYS
When we think about an array in MicroStation, we think about taking
an element and copying it multiple times. An array in VBA is a single
variable name with multiple elements in it.
Dim StartPo i nt(O to 2) as Doub l e
StartPoint(O) 4.5
StartPoint(l) 5. 6
StartPoin t( 2 ) 6.7
MyVerticies(l) . Y 5
MyVerticies(l) .Z 6
Set MyLine = CreateLineElement1(Nothing . MyVerticies)
ActiveModelReference . AddElement MyLine
End Sub
78 I Chapter 6: Variab les I
CONSTANTS
A constant is similar to a variable with one significant difference: a
constant value does not change.
Const PI As Double = 3.~4159
VARIABLE NAMES
Thousands of pages of text have been devoted to naming variables. The
best place to start this discussion is with the rules imposed on us by
VBA.
IB Variables must begin with an alpha character (A through Z) .
IB Variable names cannot contain spaces.
IB Name characters are A-Z, 0-9, and _ (underscore).
IB Variable names must be 255 characters or less.
IB Variable names cannot be keywords (such as 'Dim.', 'New', 'Left',
'Right', 'Form', 'Public').
IB Letters used in variable names can be uppercase or lowercase.
I Variable Names I 79
Based on the rules already identified, here are a few variable declarations
that work:
Dim ~yL'ne As LineElement
Dim txteMyText As TextEl ement
Dill strName As String
Dim db l Startx As Double
Dim intLevelNumber As Integer
Dim pt3dSta rtPoi nt As Poi nt3d
Each of the declarations shown above are legitimate variable
declarations. They follow the rules. The first, myLine, is slightly different
than the others. Each of the other declared variables begins with
characters that identify the type of variable. strName says the variable
type is a string. dblStartX says we are working with a double type
variable.
It is important to know if a project requires using variable naming
conventions. A naming convention is an additional set of rules on how
to name variables. For example, one convention may state that each
variable name begin with three characters followed by an underscore L)
character, then a name consisting of no more than seven characters.
Another convention may not use an underscore. Yet another convention
may require that the scope of the variable be identified inside the
variable's name.
As mentioned, many pages have been devoted to the topic of variable
naming conventions, so we will not spend much time here on the
subject. You should understand that naming a variable myLine or
lineMyLine or line123 does not cause your program to work any
differently than naming it elem li ne_LineA.
Naming conventions can extend beyond variable names. Procedure
names, function names, and control names can also be within the scope
of a naming convention.
Here is a link to a web page that discusses variable naming conventions:
http://msdn.microsoft.comllibrarylen-uslmodcore!html!
decon VariableNames. asp
Another way to become familiar with naming conventions is to search
online for "variable naming convention" or "Hungarian Notation".
80 I Chapte r 6: Vari ables I
Case Sensitivity
Consider the following variable declarations:
Dim myLine As LineElement
Dim MYline As LineElement
OPTION EXPLICIT
We have spoken for a while about variable types and declaring variables.
There are many arguments as to why we should declare our variables.
However, VBA does not force us to do so. It is possible to use a variable
even if it is not formally declared. When we do this, the variable takes on
the characteristics of a specific variable type when it is first used. For
example, it will be a 'Variant Double' if its value is 1.23456. Or it will
become a 'Variant String' if its value is "owhatafooliarn". One way we can
make sure we declare our variables is to use "Option Explicit" in the
I Using Variables I 81
Window Settings
OK .! I Cancel II Help
USING VARIABLES
After a variable is declared and a value is applied to it or it is set to an
object, the variable can be used any time the value is needed.
Sub Variab l eTestD ()
Dim MySalary As Dou bl e
Dim MyHourly As Double
MySalary 1234567
MyHourly MySalary I 52 I 40
MsgBox "My Hourly Rate is " & FormatCurrency(MyHourly. _
2 . vbFalse . vbFalse . vbTrue)
End Sub
REVIEW
Variables are names that hold values or refer to objects. Variables
declared within a function, procedure, or event are local to that function
and cannot be used outside of it. Variables declared in the General
Declarations area of a form or code module can be used from within the
form or code module in which they are declared. Variables declared as
'Public' inside a code module can be used anywhere in the VBA project.
Variables declared as 'Public' in class modules become read/write
properties of that class module.
We will use variables extensively throughout this book. After all,
without variables everything would be static - nothing could change.
Lines would always be drawn from the same point to the same point and
text would always be inserted at the same point and would always say
the same thing.
7 Working With Text
We work with text every day. This book is composed of text: words,
phrases, sentences, paragraphs. The ability to work with text is
invaluable in our programming.
Recall that the type of variable that deals with text is a String.
Sub TextWorkOl ()
Dim BookTitle As String
BookTitle = " Learning MicroStation VBA "
MsgBox UCase(BookTitle)
MsgBox LCa se (B oo kTitle )
MsgBox Left(BookTitle , 12)
MsgBox Right(BookT i tle , 12)
End Sub
In this example, we have a
variable named BookTitle that
LEARNING ~IICROSTATION IIBA learning microstation "ba
is declared as a String. It is
given a value of "Learning ········OKJI
83
84 I Chapter 7: Working With Text I
UCase
Fu nction UCase(Stri ng)
The UCa se function converts the supplied string to upper case.
Su b TextWork02 ( )
Di m st r NewLev el As St ring
strNew Level = In put Box( "E nt er New Leve l Name :" )
strNewLevel = UCase( strNewLevel )
Application . ActiveDes ignFi le.AddNew Level strNewLevel
End Sub
Isidewalk
LCase
Functi on LCas e (Stri ng)
The LCase function converts the supplied string to lower case.
Sub TextWork03 ()
Debug .P r i nt LCase( "LCase Lowers Capita l Letters ." )
End Su b
I VBA String Functions I 85
Debug.Print
is used to lcase lo~ers capital letters.
place text in
the < i
Immediate
Window. It is In this example we used text directly in the function instead of assigning
often used to the text to a variable.
display text to
aid in
debugging StrConv
our
Function StrConv(String . Convers ion As VbStrConv. _
applications.
To view the [Lo cale IO As LongJ)
Immediate
StrConv is used to convert the provided string through a variety of
Window, go
to the VBA parameters. The constant most used with StrConv is 'vbProperCase'.
menu View> Sub TextWork04 ()
Immediate Dim BookTitle As Stri ng
Window. BookTitle = "learning microstation vba "
MsgBox StrConv(BookTitle. vb ProperCase)
End Sub
This example uses the vbProperCase constant
to capitalize the first letter of each word.
Learning ~1icrostation Vba
[ OK]
MonthName
Function Mo nthName(Month As Long, _
[Abbreviate As Boolean = False]) As String
The MonthName function is similar to the
WeekdayName function but as the name
implies, it returns the name of the month
instead of the name of the day.
March
April
I-Iay
Sub TextWork05B () June
Dim MonthNum As Long July
August
For MonthNum = 1 To 12 September
Debug.Print MonthName(MonthNum) October
November
Next MonthNum December
End Sub
StrComp
Function StrComp(Stringl, String2, _
[Compare As VbCompareMethod = vbBinaryCompare ] )
The need to compare two pieces of text is common. Is "Sidewalk" the
same as "SIDEWALK"? Not always.
Sub TextWork07 ()
Di m str NewLevel As String
Dim l vlExistLevel As Level
strNewLevel = InputBox( " Enter New Level Name: " )
For Eac h lvlExistLevel In Appl ica tion.ActiveDes i gnF il e .Le ve ls
I f StrComp(strNewLevel , lvlExistLevel.Name , _
vbTextCompare) = 0 Then
MsgBox " The level" & strNew Level & " already ex i sts ."
Exit Sub
End If
Next
App li catio n . ActiveDesignFi l e .A ddNewLevel strNewLevel
End Sub
This procedure asks the user for a new level name. It compares the
newly-entered name with the name of each existing level name. If it
finds a match, a MessageBox displays and we exit the procedure.
StrComp allows us to specify how th e provided text is to be compared. In
the above example, the constant 'vbTextCompare' returns a value of zero
(0) when the characters are the same, independent of the capitalization .
With 'vbTextCompare', "SWalk" and "swalk" are the same.
Sub TextWork08 ( )
Debug . Print StrComp( " SWal k" , " swa 1 k " , vbTextCompare)
Debug . Print StrComp("swalk ", " SWa 1 k " , vbTextCompare)
Debug.Print St r Comp( " SWalk " . " swa 1 k " . vbBinaryCompare)
Debug.Print StrComp( " swalk " • " SWa 1 k " . vbBinaryCompare)
End Sub
88 I Chapter 7: Working With Text I
St rComp lets us know whether the provided text is the same but it also
tells us which text comes before the other. It is often used for sorting text
alphabetically.
Here is one more example of StrComp, called a bubble sort. It takes an
array of strings and sorts them alphabetically. This technique is a little
more advanced, so it may be good to return to it after we have learned
more VBA programming.
The firs t thing we do is declare an array of strings and give each element
in the array a value.
Len
Function Len(Expression)
The Len function tells us how many characters are in a string.
Sub TextWork09 ()
Dim LevelName As String
LevelName = InputBox( "E nter new level name: " &
(Must be 8 characters)")
If Len(LevelName) <> 8 Then
MsgBox "The l eve l na me must be 8 characters. Try again. "
End If
End Sub
In this example, we ask the user for a new level name. We also request
that the name be eight characters long. After the value is entered, we use
the Len function to check the length. If it is not eight characters « >
means not equal to), we ask the user to try again.
Left
Fu nc ti on Le ft( String . Length As Long )
The Left fun ction allows us to provide a string and specify how many
characters we want returned to us beginning with the first character
(left) of the string.
Sub TextWorklO ()
Dim FilePath As String
Di m FileDrive As String
FilePath = Applicat ion. ActiveDesignFile . Path
FileDrive = LeftCFilePath . 1)
MsgBox "The current file is on the" & FileDrive & " drive. "
End Sub
Here, we get the path of the active design file. We then look at the first
character of the FilePath variable and put it into the Fi leDrive variable. A
MessageBox then displays the Fi leDrive variable with some other text.
Right
Function Right(String. Length As Long)
I VBA String Functions I 91
Sub TextWorkll()
Dim FileName As String
FileName = Dir("C;\Program Files\Bentley\MicroStation\*.z", vbArch'vel
While FileName <> ""
MsgBox FileName & " is a " & Right(FileName, 3) & " file ."
FileName = Dir
Wend
End Sub
This procedure displays all of the files ill the C:\Program
Files \Bentley\MicroStation folder and their file extensions in message
boxes. Since there are quite a few, it will take a long time to click the OK
button on each message box.
HINT: When a program is executing, we can break into the execution of
the code by holding down the Control key «CTRL» and press the
<Break> key. The break key is normally in the upper right-hand corner
of the keyboard.
Mid
Fun ct i on Mid ( String, Sta rt As Lo ng , [L ength] )
The Mid function allows us to specify a string and the index of the
starting character we want to have returned to us. We have the option of
specifyi ng how many characters we want to have returned or we can
leave the Length parameter empty and have Mi d return all of the
characters following the specified 'Start' character index.
Sub TextWork12 ()
Di m Boo kTi tle As String
BookT i tle = "Learn i ng MicroStation VBA "
Deb ug . Print Mid(BookTitle , 3 , 6)
Debug . Print Mid(BookTitle, 6)
Debug . Print Mid(BookT i tle , I nStr(I , BookTitle , " " ) + 1)
End Sub
92 I Chapter 7: Working With Text I
We used the Mi d function three times in
the above example, each time a little
arning
ing MicroStation VBA differently. The first time we asked Mi d
MicroStation VBA
to begin at the third character and to
return six characters in all. The second
time we asked fo r the sixth character
and each character after it. Notice how
we leave out the Length parameter entirely. The third time we did not
hard-code the beginning character. We used the InStr function to look
for the first space in the variable BookTitle and added one (1) to the
character number so we began with the character after the first space.
The length is not provided so we get everything after the space.
Replace
Function Replace(Expression As String, Find As String, _
Replace As String, _
[Start As Long = 1J, [Count As Lo ng = -lJ, _
[Compare As VbCompareMethod = vbBinaryCompareJ) As St ring
The Replace function allows us to provide a string, a character or
characters to look for, and a replacement for the character(s) we are
looking for.
Sub TextWork13()
Dim Fi lePath As String
Dim FileP ath2 As String
FilePath = Application.ActiveDesignFile .Fu llName
Fi lePath2 = Replace( FilePath, " \ ", "II " )
MsgBox Fil ePa th & vbCr & "t urn s int o" & vbC r & Fi l ePath2
End Sub
In this example we look for a backslash
then replace each one found with two
C:\Microstation VBA\docs\chapter07.dgn
forward slashes. turns into
c: //Microstation VBA//docs//chapter07. dgn
InStr
r OK"·n")
Function In St r( [ StartJ, _
[S tr in g1J, [S t r in g2 J, _
[C ompar e As VbCom pa reM et hod = vbBin aryCom par eJ )
I nS t r helps us identify where a character or group of characters appear
in a string. For example, if we look in the string ''ABeD'' for string "e",
InS t r returns the number 3 because "e" is the third character in
I VBA String Functions I 93
Su:) TextWork14()
Di m Fu'l ame As Stri ng
Dim FirstSpace As Long
Dim FirstName As String
FullName = InputBox( "En ter your full name.")
FirstSpace = InStr(l, FullName, " " )
FirstName = Left(FullName, FirstSpace - 1)
MsgBox "Your first name is " & FirstName &
End Sub
Here is another simple example of the use of the InS t r function. We ask
the user to enter his/her full name. We look for the first space in the
entered name, then get everything beginning from the start of the
Fu llName up to the character before the FirstSpace.
Sub TextWork16 ()
Dim TextElem As Tex t El ement
Dim MyMod As ModelReference
Set MyMod = Applicat i on.ActiveModelReference
Dim MyElems As ElementEnumerator
Set MyElems = MyMod . GetSelectedElements
Dim MyElem As Element
94 I Chapter 7: Working With Text I
While MyElems.MoveNext
Set MyElem = MyElem s. Current
Select Case MyE l em. Type
Case msdElementTypeText
Set TextElem = MyElem
If InStr(l . Text Elem . Text. "[BY]") > 0 Then
Text Elem. Te xt = Repl ace(T ext Elem.T ext . _
"[BY]". "JKW " )
TextElem . Rewrite
End If
En d Select
We'1d
End Sub
In this example we look at each selected element in the active file. If we
find a text element selected, we use In St r to see if a particular string is in
the text element. If it is, InStr returns a number greater than zero (0).
When we know the search string is inside the text element, we use the
Replace function to replace "[BY]" with "JKW".
This is one way to perform 'Search and Replace' operations on our files.
You could use this when you need to place the name of a contractor in
your file but the file is created before the contract is awarded. Simply use
a tag, such as [CONTRACTOR], then replace it later with the name of
the contractor.
InStrRev
Fun ction InStrRev(StringCheck As String. _
StringMatch As String . _
[Start As Long = -lJ. _
[Compare As VbC ompareMethod = vbBinaryCo mpa reJ) As Long
InStrRev, as the name implies, looks at the end of a string first instead of
the beginning. This is the reverse of InS t r which begins looking at the
beginning. Here is one way to use it:
Su b Text Work17 ( )
Di m FilePat h As String
Di m Fol derName As Str i ng
FileP at h = Act iv eDe s ig nFile. Pa t h
Fo l de r Name = Mi d( FilePath . InSt r Rev( Fi le Path . " \ " ) + 1)
MsgBox "The current file is in t he " & Foldcr Name &
"f ol der. "
End Sub
I VBA String Functions I 95
We get the path ofth e current file, then use the InStrRev function inside
a ~1 i d function to get the location of the fi rst backslash we find. Since we
don't want to display the folder name beginning with the backslash, we
add one (1) in our Mi d function to get the characters following the
backslash.
NewTextFilePath ""
XSPIrt Variantistring(O to 3)
1 xSplrt(O)
xS plrt(1)
xSplrt(2)
xSplrt(3)
"C:"
"Microstation VBA"
"docs"
"chapter07.dgn"
String
String
string
string
The variable FilePath contains the path to the active design file. The
variable xSp lit is an array Sp 1i t from FilePath using the backslash (\) as
96 I Chapter 7: Worki ng Wi t h Text I
the delimiter. Take the last element in the array (using the UBo und
function) and add a new file extension of ".extract" to it.
Next, Join the array with the backslash (\) as the delimiter into the
variable NewTextFilePath.
Lastly, create an ASCII Text file using the NewTextFilePath variable as
the file name. Inside this new file print the contents of the Fi lePath
variable.
Here is what the
fi le looks like EJle !;.dit FQ.rmat yjew tielp
in Notepad.
Su b TextWork19 ()
Dim strCharacter As String
For I = 0 To 255
Debug.Print I & vbTab & Chr(I)
Next I
End Sub
I VBA String Functions I 97
Sub TextWork20 ()
Dim s tr Copyright Not i ce As Str in g
strCopyrightNot i ce = "Learning MicroStation VBA " &
Chr(169) & "2005 "
MsgBox strCopyr i ghtNot i ce
End Sub
The Asc function does the opposite of the Chr
function . You provide a character and get
Learning MicroStation VBA ©200S
back the ASCII number - something you
might do when creating graphical user
interfaces (GUIs).
FormatCurrency
Function FormatCurrency(Expression. _
[NumOigitsAfterOecimal As Long = -lJ. _
[IncludeLeadingOigit As VbTriState = vbUseOefaultJ. _
[UseParensForNegativeNumbers As VbTriState =
vbUseOefaultJ. _
[GroupOigits As VbTriState = vbUseOefaultJ) As String
Use FormatCurrency to take a number or string then display it as
currency. In some countries, such as the U.S., this places a dollar symbol
in front of it. Other parameters include the grouping numbers with
commas, etc.
Sub TextWork21 ()
Dim MySalary As Double
Dim MySala ry2 As Do uble
MySalary = 123456.78
MySalary2 = 0 .1 234
MsgBox FormatCurrency(MySalary, 2, vbFalse , vbFalse , vbTrue)
MsgBox FormatCurrency(MySalary. O. vbFalse. vbFalse, vbTrue)
MsgBox FormatCurrency(MySalary2. 2, vbFalse, vbFa ls e, vb True)
MsgBox FormatCurrency ( MySalary2, 2 , vbTrue, vbFalse, vbTrue )
End Sub
···· OK · .. ·· ~
FormatNumber
Function Forma t Number(Expression , _
[N umOigitsAfterOecimal As Long = -lJ, _
[ I nclude Lead i ngOigit As VbTriState = vbUseOefaultJ , _
[ UseParensForNegat i veNumbers As Vb TriState =
vbUseOefaultJ , _
[GroupOigits As VbTr i State = vbUseOefaultJ) As String
I VBA String Functions I 99
FormatN umber looks the same as FormatCu r re ncy. The main difference is
that Fo rma tCu rre ncy places a currency character in front of the number,
whereas FormatNumber returns only a formatted number.
Sub TextWork22 ()
Dim MySalary As Double
Diw MySalary2 As Double
MySalary = 123456.78
MySalary2 = 0.1234
MsgBox FormatNumber(MySalary. 2. vbFalse. vbFalse. vbTrue)
MsgBox FormatNumber(MySa l ary . O. vbFalse . vbFalse . vbTrue)
MsgBox FormatNumber(MySalary2 . 2 . vbFalse . vbFalse . vbTrue)
MsgBox FormatNumber(MySalary2 . 2 . vbTrue . vb False . vbTrue)
End Sub
·m ... m
123,456.73 123,457 .12 0.12
OK 'J
FormatDateTime
Function FormatOateTime(Expression,
[NamedFormat As VbOate Ti meF orma t = vbGeneralOate])
As String
Use Fo rmatDate Time to specify a date/time and how format it. Here are
your options and the results:
Sub TextWork23 ()
Di m DateTo Format As Date
Date ToFor mat = "1 / 1/2005 4 :45 PM "
MsgBox FormatDateT i me(Date ToFormat , vbGeneralDate)
MsgBox For matDateTime(Date ToFormat , vbLongDa t e)
MsgBox FormatDateTime(DateToFormat, vbLongTime)
MsgBox FormatDateTime(DateToFormat , vb ShortDate)
MsgBox FormatDateTime( DateToFormat , vbShortTime)
End Sub
100 I Chapter 7: Working Wi th Text I
Format
Function Format(Expression, [Format], _
[FirstDayOfWeek As VbDayOfWeek = vbSunday],
[ Fir s tWee kOfYear As Vb Fi rstWeekO f Year = vbF i rstJanl])
We already have examples of specific
types of formatting:
FormatCurrency, FormatNumber, Format DateTime. These functions work
great for standard formatting situations. However, VBA does not
provide a FormatPhoneNumber function. So, how do we take ten digits
and turn them into a fully formatted phone number?
&
Use the Ampersand (&) symbol to concatenate strings. I use the
ampersand extensively in this book to take multiple strings and combine
them into one.
vbCr
We have a few constants available for use with strings, such as vbCr
constant, which is for a Carriage Return. It is similar to pressing the
<Enter> key on the keyboard. Look at previous examples of the vbCr
constant and the results it generated.
I Review I 101
vbTab
Use the vbTab constant to simulate the user pressing the <Tab> key on
the keyboard.
REVIEW
Strings refer to text. Letters, numbers, and other characters combine to
form a single piece of text. This section focused on working with these
strings of characters. You learned to capitalize, make lowercase, get the
left-most or right-most characters, split them, join them back together,
format them, and a number of other things.
Take time to work through all of the examples accompanying each of the
functions. Remember, you can step through the code one line at time by
using the <P8> button.
The next section deals with numbers.
102 I Chapter 7: Working With Text I
8 Working With Numbers
NUMERIC FUNCTIONS
VBA makes working with numbers a breeze. It doesn't do all of the work
for us, but we can do a great deal with very little pain.
103
104 I Chapter 8: Working With Numbers I
Addition
1 + 1 = 2. We learned this many, many years ago. The plus symbol ( +) is
used in VBA to add numbers. Take a look:
Sub TestAdditionSubtraction()
Dim SelPt As Point3d
Dim CenPt As Point3d
Dim CadMsg As CadlnputMessage
Di m TextElem As TextElement
Dim RotMatrix As Matrix3d
Set CadMsg = Application.CadlnputQueue.Getlnput
Do While True
Select Case Cad Msg.lnput Type
Case msdCadlnputTypeDataPoint
SelPt = CadMsg.Point
Exit Do
End Select
Loop
CenPt = SelPt
CenPt.X = CenPt.X + 1
Set TextElem = Application.CreateTextElementl(Nothing, "1" , _
CenPt , RotMatri x)
ActiveModelRe ference.AddElement TextElem
CenPt = SelPt
CenPt.Y = CenPt.Y + 1
Set TextElem = Application.CreateTextElementl(Nothing, "2", _
CenPt, RotMatrix)
ActiveModelReference.AddElement TextElem
CenPt = SelPt
CenPt.X = CenPt . X - 1
Set TextElem = Application.CreateTextElementl(Nothing, "3 ", _
CenPt, RotMat ri x)
ActiveModelReference.AddElement TextElem
CenPt = SelPt
CenPt.Y = CenPt.Y - 1
Set TextElem = Application.CreateTextElementl(Nothing, "4", _
CenPt, RotMatrix)
ActiveModelReference.AddElement TextElem
End Sub
I Numeric Functions I 105
3 1
We let the user select a point in MicroStation. We then use the selected
point as a basis for the insertion of each of the text elements we add to
the model. We add 1 to the X element of the selected point to get the
location for the text "1". We add 1 to the Y element of the selected point
to get the location for the text "2". Points 3 and 4 require us to subtract
from the X and Y respectively.
Subtraction
10 - 3 = 7. Use the minus symbol (-) to subtract values in VBA, as in the
example in the procedure Tes t Ad dit i onSub t ract io n.
Multiplication
2 X 6 = 12. Use the asterisk (*) symbol to multiply in VBA. The previous
reference works when in a math book but in VBA it is written 2 * 6 = 12.
Sub TestMultiplication ()
Dim Di stance l nlnches As Double
Dim Di stancelnMM As Double
Distance l nlnches = CDbl (InputBox( "Enter distance in inches :" ))
Distance l nMM = Distancelnlnches * 25 . 4
106 I Chapter 8: Working With Numbers I
MsgBox Distancelnlnches & " is equal to " &
DistancelnMM & " Millimeters."
End Sub
Multiplying the entered value by 25.4 converts the entered value from
inches to millimeters.
Division
There are two ways to divide numbers in VBA. No, not long division
and short division. The first method returns a very precise number.
When you want precision (and you usually do), use the forward slash (I
) symbol like this: 5 / 2 = 2.5
Square Root
Use the Sq r function to get the square root of a number. Here's one way
to use it:
SJb GetLineLength( )
Dim SelElem As Element
Dim LineElem As LineElement
Dim SelElems As ElementEnumerator
Set SelElems = ActiveModelReference.GetSelectedElements
Whil e SelE l ems . MoveNext
Set Sel Elem = SelE l ems.Current
Select Case SelE l em .Type
Case msdElement TypeLine
Set LineElem = Se l Ele m
Dim St Pt As Po i nt3d
Dim EnPt As Po i nt3d
StP t = LineE l em . StartPo i nt
EnPt = Lin e El em.En dPo i nt
Li neLeng t h = Sqr((StPt . X - EnPt.X) A 2 + _
(StPt . Y - EnPt.Y) A 2)
MsgBox " Li ne found wi th length of " & Line Length
End Se l ect
We nd
End Sub
Pythagorean's theorem is used in this example. We get the change in X
and the change in Y of the selected line. We square these values, add
them together, then get the square root of the total.
TestSinCos ()
HypLength = 10
HypAngleDegrees = 30
HypAngleRadians = 0.523598775598299
XChange 8 . 66025403784439
YChange = 5
3 11;J)
Let's use the Tan function now. The first example supposes you know the
leg of the triangle along the X axis.
TestTan1 ()
XChange = 4
HypAngleDegLees = 36.8699
HypAngleRadians = 0.643501149881057
YChange = 3.00000025679859
~I
(,
Sub TestTan2( )
Dim XChange As Double
Dim YChange As Double
Dim Pi As Double
Dim HypAngleDegrees As Double
Di m HypAngleRadians As Doub l e
Pi = Atn(l) * 4
YChange = CDbl(InputBox( "Enter Y Side Length :" ))
HypAngleDegrees = CDbl(InputBox( "Enter Angle: " ))
HypAngleRadians = HypAng l eDegrees * Pi / 180
XChange = YChange / Tan(HypAngleRadians )
Debug.Print "TestTan2() "
Debug.Print "YChange = " & YChange
Debug.Print "H ypAngl eDegrees = " & HypAngleDegrees
Debug .Print "HypAngleRadian s = " & HypAngleRadians
Debug.Print "XChange = " & XChange
End Sub
TestTan2 () A ,
YChange = 3
HypAngleDegLees = 36.8699
HypAngleRadians = 0.643501149881057
XChange = 3.99999965760191
v
>
110 I Chapter 8: Working With Numbers I
4
As we write code, it is common to make little mistakes along the way.
The world calls these "bugs" but we could call them "creative
programming:' The net result is the same: the code doesn't work. It is
helpful to test our calculations with numbers that give us predictable
results.
Arc Tangent
Sin, Cos, and Tan help when we know the angle involved. If we do not
know the angle, we can get the angle by using Atn (ArcTangent).
Sub TestATan ()
Di m Pi As Do ubl e
36.869897645844
Di m Angle Degrees As Double
Di m AngleRadians As Double
Pi = Atn (1) * 4
An gle Radi an s = Atn (3 / 4)
AngleDegrees = AngleRad i ans / Pi * 180
MsgBox AngleDegrees
End Sub
Absolute Value
The Abs function gives us the Absolute Value of the supplied number.
Sub TestAbs ()
Debug.Print "The absolute value of 4 is " & Abs(4)
Debug.Print "The absolute value of -5 is " & Abs(-5)
End Sub
I Numeric Functions I 111
Sub TestClnt ()
Deb ug . Pri nt Cl nt(4 .5 6)
Debug.Pr i nt Clnt(4 . 23)
Debug.Pr i nt Clnt( - 4 . 56)
Deb ug . Pr in t Cl nt (- 4 . 23)
End Sub
When converting from a double to an integer,
something needs to be done with the decimal
portion of the number because an integer is a
whole number. It is important that you
understand how this works. CI nt arrives at an
integer by rounding the number. Take a look
at the code in "TestCInt" and the results
shown in the Immediate window.
CLng
The CLn g function works just like the CI nt function, except it converts
the provided number to a long. You could ask, "If CLng does the same
thing as CI nt , which one should I use?" That is a good question.
Remember, that a long number can be significantly larger than an
integer. To use Cl nt on a number such as 40,000.123 would create an
overflow error. CI nt and CLng are often used when assigning a value to a
112 I Chapter 8: Working With Numbers I
variable. So, if you assign a value to a variable declared as an integer, you
should use CI nt. If you are assigning a value to a variable declared as a
long, use CLng.
Sub TestCLng ( )
Debug . Pr int CLng(4OOOO.56)
Debug.Pr i nt CLng(4OOOO.23) 40 000
Debug . Print CLng(-4OOOO.56) -4 0 001
-40000
Debug.Print CLng(-4OOOO.23) V·
,...;:;f.;
End Sub
Fix
The Fix function looks like it works the same as the CI nt or the CLng
function. It returns a number without the decimal portion of the
number. However, it works a little differently. Let's look at the results of
the code below.
Sub TestFi x ()
Debug.Print Fix (4OOOO.56)
Debug . Print Fix(4OOOO . 23)
Debu g .Pr int Fix( -40000.56)
Debug . Print Fix(-4OOOO.23)
End Sub
The Fi x function simply drops the decimal
portion of the provided number. It does not
do any rounding. Fix can return numbers
that fall within the integer and long range.
CDbl
COb 1 converts the supplied parameter to a double.
Sub TestDoubl e ()
Di m LineLength As Double
LineLength = CDbl( InputBox( "Enter the li ne length :" ))
End Sub
I Numeric Functions I 113
Val
CI nt, CLng, and COb 1 work well if the supplied parameter is numeric,
providing the number 3.14159 works with any of these functions.
However, if you pass the parameter as 2.5", an error pops up. The Va 1
function has the ability to give us the numeric value of a supplied
parameter. The best way to understand how it works is to run some code
and look at the results.
IsNumeric
Many of the functions we have just reviewed return numeric values.
I sNumer i c returns a Boolean value (True or False). It looks at the
parameter and determines if it is numeric.
Sub TestIsNumeric ()
Debug.Print I sNumer i c( "4 . 5""" )
Debug . Print I sNumer i c( "4 . 5 i nches " )
Debug . Print IsNumeric( "$5,OOO " )
Debug . Print IsNumer i c( "45 degrees " )
Debug.Pr i nt IsNumeric( "Approx. 5280 feet " )
Debug . Print IsNumeric( "23 feet 12 inches " )
End Sub
114 I Chapter 8: Working Wi th Numbers I
,I
Round
CI nt and CL ng round decimal numbers to whole numbers. The Round
function lets us specify how many numbers we want to appear after the
decimal point. Take a look:
Sub TestModl ()
De bug . Pr int 5 Mod 2
Debug.Pr i nt 7 Mod 3
Debug . Print 23 Mod 7
Debug . Print 280 Mod 2
. >.
End Sub
I Numeric Functions I 115
End Sub
Sub TestRnd ()
Dim I As Long
Dim Lower As Long
Dim Higher As Long
Di m PointCen(O To 1) As Po i nt3d
Dim PointElem As PointStringElement
Lower = 25
Higher = 50
Randomize
For I = 1 To 300
PointCen(O) . X Round((Higher Lower -'- 1 ) * Rnd(l) , 2 )
PointCen(O) . Y Round((Higher - Lower + 1) * Rnd ( 1 ) , 2 )
Poi ntCen (1) . X PointCen(O).X
PointCen(l) . Y PointCen(O) . Y
Set PointElem
Application . CreatePointStri gElementl(Nothing , _
PointCen, True)
ActiveModelReference . AddE le ment PointElem
Next
End Sub
116 I Cha pter 8: Working With Numbers I
Order of Operations
2 + 5 * 8 / 12 + 13 =?
(2 + 5) * 8 / (1 2 + 13) =?
2 + (5 * 8 / (1 2 + 13)) =?
Each of these expressions returns a d ifferent result. The numbers are the
same and the operations are the same but th e results are different.
The order in which numeric operations are carried out is important to
understand. Multiplication and division come first, addition and
subtraction come second. If there is any question, place parenthesis
around the operations you want grouped to make it clear how VBA
sh ould calculate your expressions.
REVIEW
Many software developers can work for extended periods of time
without using mathematical functions . When we are programming
MicroStation, however, we are always using numeric functions. We can
add, subtract, multiply, and divide. We can use other functions that aid
in the location of elements in MicroStation or compute lengths,
angles, etc.
9 Standard VBA Calls
MESSAGEBOXES
We used MessageBoxes to display some text with an OK button . By
default, the code pauses until the user clicks the OK button.
Sub TestMessageBoxl ()
MsgBox "Your hard drive wil l now be formatted. "
End Sub
This is just what we all want to see: A
MessageBox informing us something
Your hard drive will now be formatted.
drastic is about to happen and all we have is
an OK button to click on.
You can specify the prompt of the
MessageBox (the text that shows up) as well
as which buttons display.
117
118 I Chapter 9: Standard VBA Calls I
Sub TestMessageBox2 ( )
Di m MsgResp As VbMsgB ox Result
MsgResp MsgBox("Unab l e to open file.", vbAbortRetryIg~ore)
MsgResp MsgBox( "F ormat Hard Dri ve?", vbOKCancel)
MsgResp MsgBox( "New Level Added .", vbOKOnly)
MsgResp MsgBox("Not Connected to Internet . ", vbRetryCancel)
MsgResp MsgBox( "Do you want to continue? " , vbYesNo)
MsgResp MsgBox( "Continue Reading File? " , vbYesNoCancel)
Select Case MsgResp
Case VbMsgBoxResult . vbAbort
' Place Code He re
Case VbMsgBoxResu l t . vbCancel
' Place Code Here
Case VbMs gBoxRe sult . vbIgnore
' Place Code Here
Case VbMsgBoxResult.vbNo
' Place Code Here
Case VbMsgBoxResult . vbOK
' Place Code Here
Case VbMsgBoxResult . vbRetry
' Pl ace Code Here
Case VbMsgBoxResu l t . vbYes
' Pl ace Code Here
End Select
End Sub
If you change a file name extension, the file may become unusable.
C ·OK···· J[ Cancel
r·. · y~~· ] I No
Sub TestMessageBox4 ()
MsgB ox "Te st ing Title", vb Cri t ical, "Ti t le Goes He r e "
MsgBox "Test i ng Ti tle ", , "Ti t l e Goes Here "
End Sub
~<'''''''' ~'?>rnN"""'>:'--'~)~~"'<"""" '''- ,
;rjtle ~9~~·H~r~·:.: ~
o Testing Title
Testing Title
r·· ··OK·····]
The Title parameter displays at the top of the MessageBox. It is the third
parameter, The MessageBox only has one required parameter, the
prompt. So, to display a prompt and a title and the default button, place
a comma after the prompt, a space, another comma, and then the
prompt. When you bypass an optional parameter, leave the parameter
blank and use commas to indicate that you are providing the next
parameter( s).
INPUTBox
InputBoxes let users enter text. If a user clicks the Cancel button or
enters nothing and clicks the OK button, the InputBox returns an empty
string, An empty string is denoted in VBA as two quotation symbols
with no other character between them ("") ,
IlnputBox I 121
Sub TestlnputBoxl ()
Dim InpRet As String
I np Re t = Inpu tB ox( "Enter Level Name :" )
Debug.Print "User entered" & InpRet
End Sub
[ Cancel
The InputBox has additional parameters we can use. We will discuss four
of them here.
I~ ____J
Looking at the code and the result reveals most of the new parameters.
After the prompt and title, a default value for the InputBox is provided,
then the X, Y location where the InputBox is displayed. The X and Y
values are in pixels and are system-dependent. This means if you use 0, 0
as your coordinates, the InputBox displays in the upper-left corner of
the monitor independent of where the MicroStation window is placed.
Be careful with the X and Y location parameters because it is possible to
place the InputBox entirely off screen. It would surely confuse the user if
he could not see the InputBox and the code is waiting for a click on a
button or the <Enter> key.
122 I Chapter 9: Standard VBA Cal ls I
Now!
The Now function gives the current system date and time. This is useful
512812005 11 :29:27 A~l to make a date/time stamp. Now returns a Date type value.
Sub TestNow ()
MsgBox Now
End Sub
DateAdd
Now tells us the current date/time. DateAdd allows us to look into the
future or into the past. Here are a few examples of how to use DateAdd:
In the above example, we declare a variable as a Date then set its value to
Now. We could use the function Now in each DateAdd function. Because Now
changes from second to second, it is a good idea to set a variable to Now
and then use that variable throughout a procedure to make sure you are
basing all of your calculations on the same date/time. Use a positive
IlnputBox I 123
number as the second argument to move the result into the future. Use a
negative number to return a value in the past.
DateDiff
If you have two dates and want to know the time interval between them,
use Date Di ff . Use the same interval parameters with DateAdd and
DateDi ff.
Sub TestDateDiff ()
Dim NowDate As Da te
NowDate = Now
Debug.Print "Days " & vbTab & DateD i ff( "d" . NowDa t e . "1/ 1/3000 " )
Debug.Pr i nt "Hours " & vbTab & DateD i ff( "h". NowD ate . "1 /1/3000 " )
Debug.Print "Minutes" & vbTab & DateDiff( "n" . NowDate. "1/ 1/ 3000")
Debug . Print "Seconds " & vbTab & DateDiff( "s ". NowDate . "1/ 1/ 3000 " )
Debug.Print "Months " & vbTab & DateDiff( "m" . NowDate . "1 /1/30 00 " )
Debug . Print "Weeks" & vbTab & DateDiff( "w" . NowDate. "1/1/3000 " )
Debug . Print "Years " & vbTab & Date Di f f( "yyyy " . NowDate. "1/ 1/ 3000 " )
Debug.Print "Quarters " & vbTab & Date Diff("q". NowDate. "1/1/3000 " )
End Sub
Timer
The Time r function tells us how many seconds have transpired since
midnight. This can be useful when testing our applications to find
bottlenecks in the code. If you are working late at night, however, be
careful. At the strike of midnight, the timer function returns a value of 0
(zero) and starts counting seconds all over again.
43466.31
Sub TestTimer ()
MsgBox Timer
End Sub
FileDateTime
FileD ate Time gives the date/time the specified file was last modified.
Sub TestFileDateTime ()
Dim exeDate As Date
exeDate = Fil eDateTime
("C : \Program Files\Bentley\MicroStation\ustation.exe" )
MsgBox "Mi croStat i on Dat e/ Time : " & exeDate
End Sub
'!r~~~--/" • <~'M."""'-'" ..;~.,.~~~= ""'.~ ";''':''r~''''r!}'' .'"
C·6K-..··~
FileLen
Fi 1eLen tells the size (in bytes) of a given file.
~licroStation Size: 976896
r-·-OK-· M
] Sub TestFileLen ()
Dim exeSize As Lo ng
exeSize = FileLen
( "C: \Progra m Files \Ben tley \ MicroStation \ustatio n.exe " )
MsgBox "MicroStation Size : " & exeSize
End Sub
MkDir
rUse MkD i r to create a new directory. All parent directories must exist for
MkDi r to work. For example, to make a directory (also called a folder)
I ln putBox I 125
Sub TestMkDi r ()
MkD ir "c : \ MicroSta ti on V8A\So0 rce Code "
End Sub
RmDir
RmDi r removes a directory from the file system. The directory must be
empty, otherwise an error occurs.
Sub TestRmDi r ( )
RmDir "c:\MicroStation V8A\Source Code "
End Sub
Dir
The Di r function allows us to look for files and folders (directories). The
first time you use it, specify a path and file name (wildcards are
acceptable). 0i r only returns one file/folder at a time. If you are looking
for a group of files or folders, call Di r again and leave the parameters
empty. When Di r returns an empty string (""), you know it has returned
all of the file or folder names requested. In addition to specifying a file
or folder path/name to look for, you can specify the type of filelfolder.
Since there is a great deal that you can do with the 0i r function, we will
look at several examples and the results of the code.
Sub TestD i rl ()
Dim RootPath As String
Dim DirReturn As String
RootPath = "C: \Program Fi le s\8entley "
DirReturn = Dir(RootPath & " \ *.* ", vbDirectory )
While DirReturn <> ""
Debug.Print RootPath & "\ " & DirReturn
DirReturn Dir
We nd
End Sub
126 I Chapter 9: Sta ndard VBA Ca lls I
C:\Program Files\Bentley\.
C:\Program Files\Bentley\ ..
C:\Program Files\Bentley\Documentation
C:\Program Files\Bentley\Licensing
C:\Program Files\Bentley\MicroStation
Sub TestDi r3 ()
Dim RootPath As String
Dim DirReturn As String
IlnputBox I 127
We look in the directory "C:\MicroStation VBA \Oocs" for files with the
extension .dgn. Place the paths of these files into a dynamic array
variable named DgnFiles. When the code gets to the "End Sub" line of
code, six files have been found and placed into the array. You could write
additional code to work with the files before "End Sub".
Kill
WARNING: The Ki 11 function is permanent. Files that are 'Killed' are
not sent to the recycle bin. They are destroyed totally and completely.
Use with extreme caution.
Sub TestKi 11 ()
Kill "C:\MicroStation VBA\Docs\killtest.txt"
End Sub
This code kills a file named C:\MicroStation VBA \Oocs\killtest.txt.
The ability to delete a file is useful and necessary but must be used with
caution.
128 I Chapter 9: Standard VBA Ca lls I
Beep
Beep beeps. It offers a quick, audible clue to the user as our code
executes. Although useful to draw the user's attention to the program, it
can become annoying to have an application beep every time a user does
something.
Sub TestBeep()
Beep
End Sub
SaveSetting
Working with the Windows registry can save settings the user has set in
our software. Microsoft has created a registry path for VBA program
settings that we can easily write to, edit, and delete.
Sub TestSaveSetting ()
SaveSet t i ng "Learning MicroStat i on VBA ", "Chapter 9 " , -
"S aveS etti ng", "I t Works "
End Sub
My Computer\HKEV _CURRENT _USER\Software\VB and VBI>. Program Settings\Learning ~llcroSta tion VBA\Chapter 9
After this code is run, the necessary registry folders are added and a
registry entry named "SaveSetting" is created with a value of "It Works".
GetSetting
When a setting is in the registry, we can get it by using Get Set tin g.
Sub TestGetSetting ()
Dim RegSetting As Str in g
RegSetting - GetSetting( "Learning MicroSt~tion VBA" , "Chapter g", _
"SaveSetti ng")
Debug.Print "The Key SaveSetting value is """ & RegSetting & ""un
End Sub
IlnputBox I 129
DeleteSetting
We can save and get settings and we can delete them. As with any other
API call that deals with the removal of files or data, be careful with this
one.
Su b TestDeleteSetting2 ()
De let eSe tt i ng "L ear ni ng Micr oS tati on VBA ", "Chapte r 9 "
End Sub
Te s t Oe1ete Sett i ng2 deletes the Registry Section "Chapter 9".
Sub Te s tDeleteSetting3 ()
Delet eSet ting "L ear ning Mic roS t ati on VBA "
End Sub
Test Oe1eteSetting3 deletes the entire "Learning MicroStation VBA"
Application Name from the Registry and all of its sub-entries.
GetAIiSettings
GetA 11 Se tt i ng s , as the name implies, gets all keys under the specified
app name and section and places them into a multi -dimensional array.
"Save Setting"
"ttWorks"
"SaveSetting2"
"ttWorks2"
"SaveSetting3"
"ttWorks3"
Sub TestWriteASCIIB ()
Open "C: \output.txt " For Output As #1
Write #1 . "Fi rst l ine. "
Write #1. "Second li ne. "
Close #1
End Sub
The Wri te function places quotation marks at the beginning and end of
each line which may be helpful if you need it.
Sub TestWriteASCIIC ()
Open "C:\output.txt " For Append As #1
Print #1. "Another line 1. "
Pr int #1. "Another line 2."
Cl ose #1
End Sub
Use "For Append" when opening a file to
add text to an existing file. The above
screen shot is the result of running TestWr ite ASCI IA and then running
Tes tWr i teASCI IC.
FreeFile
It is important to provide VBA a file number that points to the file in
which you want to work. In previous examples where I used "#1" as a
file number, the code works fine because the examples are simple. If
your programs open multiple files simultaneously, you could become
132 I Chapter 9: Standard VBA Ca lls I
confused as to which number should be used. This is where FreeF i 1e
comes in handy.
Sub TestWriteASCIID()
Dim FFileA As Long
Dim FFileB As Long
FFileA = FreeFile
Open "C:\outputa.txt" For Append As #FFileA
Print #FFileA. "Another line 1."
Pri nt #FFil eA. "Anot her li ne 2."
FF il eB = Fr ee Fil e
Open "C: \outp utb . txt " Fo r Appen d As # FFile B
Print #FFi l eA. "Ano t her lin e 3. "
Print #FFileB. "An ot her 1 i ne 3 . "
Pr int #FFi leA . "Anot he r line 4. "
Print #FFileB. "Another line 4. "
Cl ose #FFileB
Clo se #FFileA
End Sub
The above example works with two files at the same time. When you use
FreeFi 1e, assign the return value to a variable. In this example, I used
FFileA and FFileB as our variable names.
Sub TestWriteASCIIE ()
Dim FFileA As Long
Di m exe Fil e As Stri ng
FFileA = FreeFile
Open "c : \exefiles.xml " For Output As #FF i leA
Pr in t #FFil eA. "<?xm l ve rs i on= ""l. O""? >"
Print #FFi l eA. "<?ms o-appl i cati on progi d=""Excel.S heet""?>"""
Print #FFileA. _
"<Workbook xmlns=""urn:schemas-microsoft-" &
"com : off ice : spreads hee t"" >"
1.5,2.5,O,Note 1
34.2,54.12,O,Note 2
43.2,1.43,O,Note 3
22.3,33.4,O,Note 4
The example above left uses the Immediate window to show each line in
the file we read. Above right is the file in Notepad. Use Line I nput and
the file number to read a text file one line at a time. Continue reading
until you reach the End Of File (EOF) . It's time to expand on this
example.
Note 4
Note 1 Note 3
Sub ForNextA()
Dim I As Long
For I = 1 To 10
ActiveDesignFile.AddNewLevel "NewLevel "& I
Next I
End Sub
After this code is run, 10 new levels are created named "NewLevel 1"
through "NewLevel10".
For ... Next requires a variable. This example uses a variable named I
declared as a long. The first time you create a new level, I holds a value of
1 (one). The next time, I holds a value of2 (two). This continues from 1
to 10. I eventually holds a value of 11 (eleven) which, since it is out of the
range specified, exits the For ... Next loop and then VBA continues to
execute the code below the For ... Next loop.
Sub ForNextB ()
Dim I As Long
For I = 1 To 10 Step 2
ActiveDes i gn Fi l e . AddNew Level "New LevelB " & I
Next I
End Sub
I added an optional parameter to our For ... Next statement. It is a Step
parameter. By default, For ... Next loops increase the index parameter
by a value 1 (one) each time it is run. When this code is run, however,
''1'' gets values of 1, 3, 5, 7, 9, then ends with a value of 11 and exits the
loop because we are using "Step 2".
Sub ForNe x tC ()
Dim I As Long
For I = 10 To 1 Step -1
ActiveDesignFile . AddNewLevel "N ewLevelC " & I
Next I
End Sub
I Controlling Code Execution I 137
I just changed our Step parameter to -1. This means ''1'' gets the
following values: 10, 9, 8, 7, 6, 5,4,3,2, 1 and then has a value of 0 and
exits the loop because 0 is outside the bounds of the loop.
. . . .... . . ': C
· .. ..
OOOGCD
· ' ,' . "
OOOOOC
OO' OO"OC
. ... . - . . .. . -~ .. -. . . "
While . . . Wend
When using Whi 1e ... Wend we are uncertain how many times we need to
repeat a block of code. The code between the While and Wend
138 I Chapte r 9: Standa rd VBA Ca ll s I
statements continues to execute as long as the While statement is true .
Here is a portion of a procedure we already looked at in this chapter.
Do . . . loop
Do ... Loop is very similar to the While ... Wend statement. However, it is
more versatile. Here is one example:
Sub TestDoWhileA ()
Dim CadMsg As CadInputMessage
Dim InsPt As Point3d
Dim CellElem As CellElement
Do While True
Set CadMsg = CadInputOueue . GetInput
Select Case CadMsg.InputType
Case msdCadInputTypeDataPoint
InsPt = CadMsg.Point
Exit Do
End Select
Loop
Set CellElem = Application.CreateCellElement3( "Column ", _
InsPt , Tru e)
ActiveModelReference.AddElement CellElem
End Sub
I Control ling Code Execution I 139
One of the great things about a Do ... Loop statement is we can use "Exit
Do" to get out of the loop at any time. This example allows the user to
select a point in MicroStation. When that happens, we capture the point
and exit the Do Loop. Then we use the captured point to insert a new
cell.
Here is another variation of the above procedure. In this next example,
the code will continue inserting cells until the user hits a key on the
keyboard.
Sub TestDoWhileB ()
Dim CadMsg As CadlnputMessage
Di m InsPt As Point3d
Dim CellElem As Cell Element
Do While True
Set CadMsg = CadlnputOueue . Getlnput
Select Case CadMsg.lnputType
Case msdCadlnputTypeDataPo i nt
In sPt = CadMsg.Point
Set Cel l Elem =
Appl i cat i on . CreateCellElement3( "Column ", _
I nsPt , Tr ue)
ActiveModelReference.AddElement CellElem
Case msdCad Inpu tTypeComman d
Ex it Do
En d Select
Loop
End Sub
When using "Do While True", we remain in the loop until we either
"E xit Do" or "E xi t Sub" or "Exit Function". "E xit Do" to get out of the
loop and continue to execute the code in the procedure or function. Use
"Exit Sub" and "Exit Functi on" to exit the procedure or function.
Sub TestDoWhileC ()
Dim TextToPl ace As Str i ng
Dim LineNumber As Long
Dim NotePt As Po in t3d
Dim CadMsg As CadInputMessage
Dim TextElem As TextElement
Dim RotMat As Matrix3d
Do ~!hi 1e True
140 I Chapter 9: Standard VBA Calls I
Set CadMsg = CadlnputOueue . Getlnput
Sel ec t Case CadMsg. Inp utType
Case msdCadlnputTypeDataPoint
NotePt = CadMsg . Point
Set TextElem = App 1 ication.Create T extElementl(Nothing. _
"0 Not e", Note Pt , Ro t Ma t )
Acti veM od elRefere nc e.AddEleme nt TextEle m
Exit Do
End Select
Loo p
TextToPlace = "The following notes supercede all prior notes."
LineNumber = 1
Do
No t ePt. Y = NotePt.Y - 0 .375
Set TextElem = Applicat i on . Create Text El ementl(Nothing,
Li neNumber & ". " & TextToPl ace,
NotePt , RotMat)
Act i veModelReference.AddElement TextElem
LineNumber = LineNumber + 1
TextToPlace = InputBox("Enter Note :" )
Loop While TextToP l ace <> ""
End Sub
This procedure uses two separate Do Loop statements. Let's focus on the
second one. When using "Do" by itself, the code inside the loop executes
at least once. Then, rather than placing the conditional statement at the
beginning of the "Loop", place the conditional statement at the end of
the «Loop:' This example allows the user to select a point. We
automatically enter «# Note" where the user selected the point and enter
"I. The following notes supersede all prior notes:' below the «# Note"
text.
Now that we added a header and a standard note, we allow the user to
begin entering additional notes. Each additional note is placed 0.375
units below the prior note. When the user presses the OK button
without entering anything in the InputBox, the Loop completes because
TextToPlace is an empty string and the "Loop" condition is no longer
true.
I Control ling Code Execution I 141
If ... Then
Use If ... Then statements to execute a particular block of code only if a
specific condition evaluates to a value of true.
Sub TestlfThenA ()
Di m LevelName As String
LevelName = InputBox( "En t er Level Name (3 lette rs on l y) " )
If Len(LevelName) = 3 Then
ActiveDesignFile . AddNewLevel LevelName
End If
End Sub
If the user enters something with three characters, add the new level. A
very simple implementation of an If ... Then statement.
Sub TestlfThenB ()
Di m LevelName As Str i ng
LevelName = InputBox( "Enter Level Name (3 letters on l y) " )
If Len(LevelName) = 3 Then
ActiveDesignFile . AddNewLevel Leve l Name
Else
142 I Chapter 9: Sta ndard VBA Ca lls I
MsgB ox Le velName & " ha s" & Len( Le vel Name) & _
" characters ."
End ! f
End Sub
In this example, look at the number of characters and create the new
level if it is three characters in length. Also add an "Else" statement to
handle situations when the length is not equal to three. Display a
MessageBox showing the number of characters entered wh en the entry
has anything other than three characters in it.
Sub TestlfThenC ()
Di m Level Name As String
LevelName = InputBox( "Enter Level Name (3 letters only) " )
If Len(LevelName) = 3 Then
ActiveDesignF i le . AddNewLevel LevelName
ElseIf Len(Leve l Name) > 3 Then
Act i veDesign Fi le . AddNew Leve l Left(LevelName . 3)
Else
MsgBox Leve l Name & " has " & Le n( LevelName) &
" characters ."
End If
End Sub
TestI fT he nC introduces an El seIf statement. You can use El se l f
statements inside If ... Th en statements and provide a secondary If
statement. You can use multiple E1s elf statements before an E1s e
statement.
Select Case
Imagine asking a user to enter a level name then looking at the first
character of the level name. You could use an If ... Then statement with
multiple E1s el f statements or a Se 1ect Ca s e statement.
Se 1ect Ca se lets us provide the condition and then multiple possible
matches for the condition.
Error Handling
In a perfect world with perfect developers, errors would never occur.
We, however, are not perfect, so errors do pop up once in a while. VBA
gives us some tools to deal with errors.
Sub TestErrorHndA ( )
On Error GoTo errhnd
Di m Li ne Le ngth As Doub l e
LineLen gth = CObl(In put Box( "Enter Lin e Le ngt h: " ))
Exit Sub
errhnd :
Select Case Err . Number
Case 13 ' Type Mi smatch
MsgBox "L i ne Lengths must be numeric ."
Err.Clear
End Select
End Sub
In TestErrorHndA, ask the user for a line length. As you write code
assume the user knows to enter a numeric value but if the user enters
144 I Chapter 9: Standard VBA Calls I
something like "10 meters", you run into problems. If you don't handle
the error, the user sees this:
Type mismatch
!;.nd tleip
errhnd :
Select Case Err . Number
Case 13 ' Type Mi smatch
MsgBox "Line Lengths must be numeric ."
Err . Clear
End Select
I Controlling Code Execution I 145
Each error has a number associated with it. Use a Select Case statement
to handle different types of errors differently. In this example, only look
at error number 13. If any other error occurs, it is not handled by our
Se 1ect Case statement and the procedure finishes with End Sub.
So, how do we know what error numbers we need to deal with? This is
an excellent question. Let's go back to TestSe l ectCaseA covered a few
pages ago. Run that macro and enter "aaa". Everything should run fine.
Run it again and enter "aaa': What happens?
If you enter the same level name twice, the code attempts to create a
duplicate level. We see this MessageBox which gives us some good
information. First, it tells us the error number. -2147221504 and a
description that "Level name is duplicate". That is good to know because
we can add that number in the error handling portion of our code. We
can also hit the Debug button to go to the line of code in question to see
exactly where the error occurs.
errhnd:
Select Case Err.Number
Case 13 ' Type Mi smatch
MsgBox "Line Lengths must be numeric. "
Err.C l ear
Resume Next
End Select
End Sub
146 I Chapter 9: Sta ndard VBA Ca lls I
TestE r rorHndB is identical to TestErrorHnd Aexcept for one line. Adding a
Resume Nex t statement in TestErrorHndB executes our procedure to
continue the line after the error occurred.
errhnd :
Select Case Er r.Number
Ca s e 13 ' Type Mismatch
MsgBox "Line Lengths must be numeric . "
Er r . Clear
Resum e
End Select
End Sub
Here is another slight modification that uses a Re sume statement instead
of Res ume Next. Resume asks VBA to again try the line of code where the
error occurred, whereas Resum e Next ignores the line of code where the
error occurred and moves to the next line.
Su b TestError Hn dO ()
On Error Resume Next
Di m Li neLength As Doub l e
Li ne Length = CDb l (InputBox( " Enter Li ne Length :" ))
End Sub
Instead of attempting to trap errors as they occur, you can tell VBA to
ignore errors altogether and move to the next line using "On Error
Resume Next".
Although "On Error Resume Next" appears to be somewhat sloppy (and
it can be), it can be useful. Consider this next procedure:
Sub TestErrHndE C)
On Error Resume Next
Dim MyExcel As Object
Set MyExcel = GetObject( . "Excel.Application " )
If Err . N mber <> 0 Then
I Controlling Code Execution I 147
Err . Clear
Set MyExcel = CreateObject ( nExcel.Application " )
End If
On Error GoTo errhnd
MyExcel.Visible = True
"1sgBox MyExce 1. Act i veSheet . Narr.e
Exit Sub
errhnd :
MsgBox "E rror " & Err.Number & " has occurred. " & voCr &
Err.Descr i pti on . vbCritical . "E rror In TestErrHndE "
Err . Clear
End Sub
In this example, we use On Error Resume Next because we are
anticipating the potential for a specific error.
member.
I Review I 149
After selecting an item in the Object browser, you can get additional
information and, at times, sample code, by pressing the <Fl> key.
DateDiff Function
See Also E:<ample :':, ..
Returns a Variant ( Long ) specifying the number of time interva ls between two specified
dates.
Syntax
DateDiff(interval, date1, date2[, firstdayof,,'eek[. firstweekofl1ear]J)
The DateDiff function syntax has these named arguments :
Part Description
date 1 , date2 Required ; Variant (Date). Two dates you want to use in the
cal cu lation.
firstda vofwe ek Optio nal. A constant that specifies the first day of the week. If
not specified, Sunday is assumed .
firstw eekofy ear Option al. A constant that specifies the first week of the year .
If not specifie d, the first week is assumed to be t he week in
which January 1 occurs.
Settings
The interval argument has these settings:
v
REVIEW
Many procedures and functions are built into VBA. You do not need to
write a function that tells the current date and time because we have the
Now function. Similarly, you do not need to write complex code that
stores your application information in the Windows registry as you can
use the Sa veSet t i ng and GetSet t i ng procedures.
150 I Chapter 9: Standard VBA Calls I
10 Visual Interface
151
152 I Chapter 10: Visual Interface I
allow the user to pick the insertion point in addition to being able to
enter the insertion point by hand. Let's move things around a little.
How does this look? Better? OK. "",~'J(T.i'~" )~""7"'-""'~'r j\"''''''''''''''~'''" ."'.......-'l:~~,
jJ~~_~__~J
begin writing code behind the
interface. We'll get into that a
little later. First, let's talk about
Insert Cancel
the controls we can add to our
user forms.
The toolbox shows us the controls we can place
Conlrols I on our forms. Except for the pointer arrow, each
,~- A abl ~ [ffij of the items shown are visual elements we can use
17r.;=!O-, in our interface design .
..!..l":'};:.YJ1dl
Properties
You can set properties at design time (that is while you are designing
your interface and writing code) or at run-time (when the program is
being run). Control properties are modified at design time by using the
Properties window.
I Properties, Methods, and Events I 153
Priva t e sub
MsgBo x Ch ec kB ox l . Val u8
NewLe v e lN a me t xtLevel Na me .t e
E nd Su b @, i·.II.E'tlt.J~.
< i @i' TextAlign
M;...,;;;;;;;;;...._ _ _......._ _ _ _ _ _ _ _ _ @ , TextLength
@i' Top
@, Value
@i' Vi sible
@'Width v
Control Events
Now, let's look at using control events. You write code for control events
in the form's code area, which looks identical to a code module but is a
little different. All controls currently inserted into the form are itemized
in the left-hand ComboBox. When a control is selected in the left
ComboBox (CommandButton 1 is selected below), we can then select
an event in the right-hand ComboBox (the click event is selected
below).
NewLevelName
I Common Control Properties I 155
When you select an event not previously selected, VBA fills m the
framework of the event for us.
This is KeyPress event occurs when a key is pressed. Some events pass
parameters we can look at, such as the KeyPress event passing the
"KeyAscii" parameter. We can use this parameter as a variable to see
which key was pressed.
Here the MouseDown event tells which mouse button was pressed (The
button parameter), the state of the <Shift>, <Control>, and <Alt> keys
when the button was pressed down (the Shift parameter), and the
location on the mouse (X, Y parameters) when the mouse button was
pressed.
In addition to supplying us with values, some parameters can be
modified. For example, the KeyAscii parameter in the KeyPress event
can be assigned a value of 0 (zero) inside the event to cause our program
to act as though no key was pressed.
Name
What's in a name? We work with controls by addressing them by name.
We then identify the property we want to get or set, or the method we
want to use. The name and property (or method) are separated by a
period. Take a look:
The variable XVal now holds the value of the Text property of the
txtXValue control.
Since we are discussing control names, we should say a word or two
about naming conventions. Control names follow the same rules as
variable names. They must begin with a letter, cannot contain spaces,
etc. Some naming conventions suggest that TextBox names should begin
with "txt", Labels should begin with "lbl", ComboBoxes should begin
with "cmb", etc. As with variable naming, if a convention needs to be
followed, you should follow it. If not, at least name the controls
something that makes sense. By default, controls are named such as
"TextBoxl", "TextBox2", "TextBox3" and so on.
Left, Top
All controls have a Left property and a Top property. These properties
dictate where to place the control on the form. The top left corner of the
form is (0, 0). So, if a TextBox is given a Left value of 0 and a Top value of
0, it appears in the upper left corner of the form.
I Common Control Properties I 157
Width, Height
All controls have Width and Height properties. These properties
determine the size of the control. We should consider the size and shape
of the controls we use. Just because a TextBox can have a width of 20 and
a height of 20 doesn't mean it should. If a TextBox is a set to be a single-
line TextBox, it may make little sense to have its height greater than is
necessary to display a line of text. If on the other hand, you want to
display a square CommandButton, make the width and height
properties the same.
Visible
Why would you want to place a control on a form and then set its Visible
property to false? Controls are to be seen, right? There are times when
you may want to make a control visible or invisible based on other
conditions. Setting a control's Visible property to false makes it invisible
at run-time but it is still visible at design-time. The Visible property can
be changed at run-time between true and false as needed.
Enabled
When a control has its Enabled property set to true, you can interact
with the control at run-time. When Enabled is false, the control turns
gray and you we are unable to interact with it. The Enabled property
does not affect the visibility of the control, only the interaction.
TabStop
Pressing the <Tab> key at run-time moves from control to control. If
the TabStop property of a control is true, the control receives focus in its
turn. If TabStop is false, the control does not receive focus during
tabbing.
Tablndex
The TabIndex property determines the order in which controls receive
focus as you Tab from control to control.
158 I Chapter 10: Visual Interface I
Tag
Use the Tag property to do as you see fit. One thing you can do with the
tag is assign it a default value for a TextBox and give the user the ability
to click a "Load Defaults" button, causing the Tag property to populate
the Text property.
ControlTipText
The ideal interface gives the user the controls necessary to perform the
proper functions without needing to refer to a user manual each time
the program is used. You could place a lengthy Label next to each
control explaining details about why the control is there and how to use
it, but this would clutter the interface. Hold the mouse cursor over a
control for more than a second or two to make VBA display the control
tip text.
Level Name: r-
~
IType in a Level Name that is 4 characte rs long . I
A Label
Labels help users know what to enter or select. Properties of note are as
follows:
abl TextBox
The TextBox allows users to enter text or display text, often in single-
line mode so text is displayed in one line. You can stretch a TextBox
vertically to display multiple lines.
I Common Control Properties I 159
Properties
Events
~ (OMBOBox
Use ComboBoxes to allow users to drop down a list of items to choose
from, or depending on the Style property, users can type into a
ComboBox if the item is not listed.
Properties
Methods
Events
~ llSTBox
Use ListBoxes to allow one or more items to be selected from a list.
ComboBoxes are similar but limit selection to one item at a time and, of
course, ListBoxes do not "drop down".
Properties
Methods
Events
p" CHECKBox
CheckBoxes allow us to specify the selection of an item. Multiple
CheckBoxes can be on one form and behave independently from one
another. Using a pizza order analogy, you could use a CheckBox to
specify each topping.
Properties
Events
r. QPTIONBuTTON
Use OptionButtons when you want the user to make a single choice
between several possible items, such large, medium, or small. You could
use three OptionButtons for each selection.
ITogg le Button I 163
Properties
lf
White'; IfBlue for the color, use two group names for
If
Events
~ TOGGLE BUTTON
The toggle button looks like a CommandButton but it behaves more like
a CheckBox. When selected, it looks indented. You typically see toggle
buttons used to specify whether a font is bolded, underlined, or
italicized.
Properties
Events
XV" FRAME
[J
Frames are control containers. This means that controls can be placed
inside of them. If a frame's Visible property is set to false, all controls
inside it become invisible. When a frame is moved, all controls in it
move with it. Use frames to organize groups of controls.
Properties
.-J COMMANOBuTTON
Use CommandButtons to give users something to click on, such as these
(commonly captioned): "OK", "Cancel", "Print", "Open", and "Close".
Properties
Events
Properties
Methods
Events
..:J MULTIPAGE
The MultiPage control is a control container where each page has its
own collection of controls. Right-click a tab and select a function to add,
rename, delete, and reorder pages.
Properties
Methods
Events
~ SCROLLBAR
.:!:I
Scroll Bars allow the user to select and change numeric values. The
rectangle that moves as the value changes is called the Thumb.
Properties
Events
! I SPiNBuTTON
Use the spin button to allow users to change numeric values. It is similar
to the scroll bar but does not have a Thumb.
I Image I 167
Properties
Events
GZJ IMAGE
Use the image control to display images in your interface. Acceptable file
formats are .bmp, .gif, .jpg, .wmf, and .ico.
Properties
Z
: r-1:----- ~I
10
The first controls are two ComboBoxes.
By default they are inserted with thePICK
Insert Cancel
Change the names to cmbLevels and
cmbCelis. Next, insert two labels and
I
place them on the left-hand side of the
ComboBoxes. Make the caption properties for these labels "Level" and
"Cells':
The next section is a group of controls inside a frame. Insert the frame
and change the frame caption to "Insertion Point". Then insert the text
boxes, labels, and CommandButton. Change the TextBox names to txtX,
txtY, and txtz. Name the CommandButton c mdPic k and the caption
"Pick".
The last controls you will add are two CommandButtons named
cmdlnsert and cmdCancel with captions of "Insert" and "Cancel".
We are using the AddItem method to populate the Levels and Cells
ComboBoxes with the names of the levels and cells in the
ActiveDesignFile.
Now that code is in place to populate the ComboBoxes, press <FS> to
run the code and make sure everything works. The ComboBoxes should
have the names of the levels and cells in them. Click the "X" in the upper
right -hand corner of the form to close it and go back into VBA.
One more thing needs to be done to the ComboBoxes. We want the user
to select the level or cell but we do not want the user to be able to typ e
anything into these two ComboBoxes. To accomplish this, change the
Style properties of the ComboBoxes to 2 - fmStyleDropDownList.
The next thing is to write some code so only numeric values can be
entered into the text boxes. Do this by working with the KeyPress event
of the text boxes.
170 I Chapte r 10: Vi sual Inte rface I
Right -click on the top TextBox and select View Code. This takes us to
the Change event of the TextBox by default. Selecting KeyPress in the
Procedure ComboBox takes us to the KeyP r ess event .
KeyAsci i 0
End If
Case Else
KeyAscii 0
End Select
End Sub
errhnd:
Err. Clea r
End Sub
Let's look through the code slowly. First, we declare some variables.
That's the easy one. Second, we begin listening to the Input Queue. If the
user picks a point, we do the following:
[E Place the selected X, Y, and Z point elements into the three text
boxes.
[E Ifboth the Levels ComboBox and Cells ComboBox are not
empty, insert the selected cell at the selected point and then
change its Level property to reflect the selected level.
If any other Input occurs or an error occurs, we exit the procedure.
If there is any concern about typing in all of the code shown for this
project, the VBA Project named ChapterlO.mvba can be found on the
CD included with this book.
Each line in the text file gives us the X, Y, Z elements of the text insertion
as well as the label we want placed at the X, Y, Z point.
1 1 0 1
2 2 0 2
3 2 0 3
3 3 0 4
3 3,5 0 5
3 4 0 6
3 5 0 7
Next
End Sub
The 'btnPlotPoints' button looks at each item in the list and from it we
get the X, Y, and Z elements of the text origin as well as the text to
display.
When the user clicks the 'Cancel' button, execute the following code:
Pr i ntF oo t e r FFi le
End If
If chkT i tl e . Va lu e = Tr ue Then
Print Hea der "TI TLE " . FFi l e
Pr intLi ne Act i veOes i gn Fil e . Tit l e . FF ile
Pr in tFooter FFi l e
End If
Cl ose /l FFi l e
End Sub
We have saved the easiest event for last.
Views
11 O!J Views
11 ~
Zoom IPan I Zoom Pan I
~
OUT ...iI J ...tJ IN
...J
.::l
...iI J ...tJ
I use the MultiPage control here. This provides tabs and unique
interfaces on each tab. I also use a few labels, a ComboBox, and three
scroll bars with Min values of -500 and max values of 500. When the
form is initialized, I populate the ComboBox with the View indexes. I
also set an initial value for the Pan scroll bars.
When you right-click on an existing tab in the MultiPage, you access
controls to add tabs (select "New Page"), to rename, delete, or move the
order of the pages.
cmbViews.Listlndex = 0
ViewCen = Act i veDes i gnF i le.V i ews(l) . Center
scrX.Va l ue Vi ewCen.X
scrY.Value = ViewCen.Y
End Sub
Here is the Initialize event of the UserForm. We add each View's Index
to the ComboBox named cmbViews. Select the first element by
assigning the ListIndex value to O. The last step is to get the current
center of view 1 and apply the X and Y values to the scroll bars srcX and
srcY.
Scroll bars have two events with which we will be working. The first,
Change event, is triggered each time the value of the scroll bar changes
except for when the Thumb is being scrolled. The scroll event is
triggered as the Thumb is dragged between the min value and max
value.
We are going to create two procedures for performing the zoom and pan
operations:
REVIEW
We will use user interfaces in a number of areas in the remainder of this
book as we learn more about MicroStation VBA. Keep the following
points in mind:
IB All controls have properties, methods, and events.
IB Address a control's properties and methods by the control
name, typing a period, typing the property or method, and then
providing parameters when required.
IB At run-time, even ts are triggered as the user interacts with your
interface.
IB Display user forms using the Show method.
IB Use the Initialize event to set values and populate controls prior
to the fo rm being displayed.
186 I Chapter 10: Visual Interface I
11 The MicroStation Object
Model - Objects
In th is chapter:
[B The Object Browser
[B Auto List Members
[B The MicroStation VBA Help File
[B Adding Watches
[B The MicroStation Object Model
187
188 I Chapter 11: The Mic roStation Object Model- Objects I
The Object Browser has two combo boxes at the top. The top -most
combo box allows us to narrow the classes to a specific Library. In the
image above, the MicroStationDGN Library has been selected. The only
classes now shown belong to the MicroStationDGN Library.
When we select "Application"
in the Classes ListBox, the
IMembe rs of 'App lication'
@I Name AI
"Members of 'Application'"
fJ OnOes ignF ileC losed
show up in the Members
fJ OnOes ignFil eOpened
ListBox. The Members
~=-~ OpenOesignF ile
ListBox displays the
":0% Op enO es i gnFi IeF 0 rP ro gram
Properties, Methods, and
@I PaU1
Events of the selected Class. :,=.% Pi v ;
IThe Object Browser I 189
Three primary member types are shown in the Members ListB ox.
First are Properties. "Name" and "Path" are properties of the
Application Object.
Methods "OpenDesignFile", "OpenDesignFileForProgram" and "Pi"
belong to the Application Object.
Events "OnDesignFileClosed" and "OnDesignFileOpened" also belong
to the Application Object.
When we select a member in the list, we are shown the Declaration for
the selected member at the bottom of the Object Browser.
Function OpenDesignFile(OeslgnFileName As String. (ReadOml,'As Booleanl.
=
IV7Action As MsdV7Action msdV7 ActionAskUserl) As Desi'UlFile
Member of MicroSt~tionDGtI.A!l!l l ic~tion
IMicroSbrtionDGIl
I
v-I
~"' i
~ r Iitll .~ ~
Notice the cursor over the Hide/Show Search Results button in the
Object Browser. A search for "text" in the MicroStationDGN Type
Library results in numerous results. So, if we do not know the specific
Class or Member we need, we can use the Object Browser to search
for it.
190 I Chapter 11: The MicroStation Object Model- Objects I
~:~B~[~~~a=:~~~it~~~~~~n jl
End Sub @i' iA¢.$.~~~~g~r:
~ ActiveDes ign Fil e
@i' ActiveMo delRefere nce
@i' ActiveSellin gs
I1j1 ActiveWorkspace
""~ AddAllachme ntEventsHandler
,,~ Ad dC ha ngeTra ckEventsH and ler
The "List Members" list displays as we work in VBA. Once the list
displays, we can use the arrow keys and page upl down keys to scroll
through the list. If we select "ActiveDesignFile" at this time and press the
period key, we see the following:
@i' Comments
@' Company
The ''Auto List Members" list allows us to 'drill down' through an Object
Model.
~~.--~~- ~?'r-;-:~ ;-M'J""iR·e,. ... .., "'~<-~-,...~"'-..;,.'" ~> ''''_''fi;;:;<p r' ~Tq h • fl ~ -" -~,""""'f'''' "~~',;: ~~-> ,. • , ~t~ r- OJ "< ""'~£ -----,. ~
&1 MicrC!SIi!tiop VB V}sual Basic for AppiicaticlV5 Help.,;.,., .,,,,,~\;,~;,,,, ...":.,:'",< ;:{~.'~h"""" :"'o>~2{,","""~ ,;,' ~l§1~
~1Il <? c:i> ~~.
-~~--~ LOC~~ _ _8_ac_k__ ~~~~~·····rP_ri....nl~-=O:::p.::.tio::.n.::.s_ _ _ _ _ _ _- - - - - - - - - - - - - - - - - - - : -1
,kontents Index l .2earch I Faili : ~
Ap pli cati o n object structu re
T~pe in Ihe ke~l:!ord 10 find: Th e structure of the app li cation object is sho wn belo w:
IApplication Strueture
Application Object
r- ,e.ctl 'leDeslgnF I I e {OasignF i IS}
~.. "
ApplicationElement Object ..... :,
App!icationlO Property r-- Act i vel,'l ode I Reference {M ode I Refe r enc e}
ApplicationObiectConnector Obje
A ppl~ H o ri20nlaIScalingF i, F o rE M f t-- Ac ti v ~S e ttin~s { Sett i ngs}
ApplyRotation Property
ApplyS aveaViewE!ement Methoc t-- Act ; v eWurl\ sp ,Jce (WQ~kspcce)
Ap p l~Verl icaIS ca ling Fi,Fo r EM F ~
Appro:'limateWitMrcs Method t-- A tt'Jched Ca ll L ib"cry {Ce II Librcry }
ArcE lement Object
Area Melhod
AreaModeHofe Property
r-- Ccd I n" utOu eue { CadI nputQueue f
AreaPaUem Object t-- Caption ( String )
AreaPatternDelta Property
ArePolesCollinear !vi elhod
ArrowSymbolCeliName Propert!,'
t-- Corrmar.,j 5tate (ComrnandSt a te)
Allow TerminatorChalSymbol PIO~
Arrow TelminatorFont Ploperty t-- C u'TsntCr aph i c.Grcup { L ong}
Allow TerminatorSymbolT ype Pial
As.AppficationElement Propelty r-- F u I I Noms ( St~ i no f
As.AlcElement PlOperty
AsAttachment Properly Appl ica t i on -r-- HosActlveDesi gnFl l e {Boo l)
AsAu~ilialyCoOidinateSystemElell
AsBsplineCurveElement Properl!,' t-- Has A ctl v eMod~ I Refe r'e nG" {Bcal)
AsBsplineSurfaceElement Proper
AsCeUElement Properl!,' t-- He ight {LonQ )
AsChainableElement Property
AsClosedE lement PlOperl!,'
t-- [s Acaderr,i eV er- s i on (800 I )
,,'
AsComplexE lemenl Propelly
AsComplexShapeElemenl Ploper S.:
AsComplexStringE!ement Properl! t-- IsCel IL i br-or" y Attoch"d (Bao l f
AsConeE lement Ploperl!,'
AsCul veElement Ploperly t-- IsRegis tered ( Boo l f
AsD imensionElement Property
AsOroppableElement Propelty t-- I s Ser i (] I i Z6<j {8 00 I }
AsE liipseE lement Properly
AsE liiplicalE lemenl Property r-- Il ey inArguments {String)
AslntersectableElement Property
AsLineE lement Properly t-- LaftFcs i t i on {Long)
AsMulliLineElement Property
t-- Na ma {String}
Qi spla~
,< -_._-'- '- ) ,
Once in the MicroStation VBA Help File, we can click on the Index tab
and type "Application Structure" in the 'Search' box. Selecting
''Application Structure" from the Index list displays the MicroStation
Application Object structure. Select ''Application Object" from the list to
display a description of the object with hyperlinks to Properties,
Methods, Events, Example Code, and See Also which displays a list of
associated objects.
192 I Chapter 11: The MicroStation Object Model - Objects I
ADDING WATCHES
We have introduced adding Watches previously. Adding a watch to a
variable is an excellent way to see its Properties. Some of the Properties
are actually other objects that we can continue to traverse by expanding
the item in the tree. Others in th e list are Collections of Objects that we
can examine in the Watch window.
DesignFileiOesignFile
ModelReferenceiModelRef, I
Settings,Settings
WorkspaceNVorkspace
<No cell library> CeliLibrary ;;
8spline,Bspline I'
CadlnputQueue/CadlnputQ' I' ,
"chapter11 .dgn (2D - V8 DGN) - Microstation V8 XM Ed~ion" string I:
CommandStatelCommandS I:.
CurreniGraphicGroup Long I;
CursorlnformationlCursorlr \'
ObjectNBProject
"C: 'Program FileslBeniley'Microstation'J.Jstation .exe" string
HasActiveDesignFile True 800lean
HasActiveModelReference True 800lean
Height 1208 Long
IsAcademicVersion False Boolean
IsCeliLibraryAttached False 800lean
IsRegistered True 800lean
Is Serialized True 800lean
KeyinArgumenis string
LeftPo s~ion -4 Long
MdlLib MdlLibrarylMdlLibrary I;'
MessageCenier MessageCenieriMessageC 1\
Name "ustation" string r.
Path "C:'Program FileslBeniley'MicroStation" string I:
ProcesslD 3160 Long
RasterManager RasterManager lRasterMan I
standardsCheckerConirolier standard sCheckerConirolh I
TopPos~ion -4 Long I.
User Name "Administrator" string
V8E ObjectN BE
Version "Version 08 .09 .00.92 W ndows x86" string
Visible True 800lean
W eith 1608 Long
Application Object
The Application Object points to the MicroStation Application.
Accessors
Sub TestApplicationA ()
Dim MyApp As New Application
MsgBox MyApp . Path
End Sub
Application
~ Property ACSManager As ACSManager (read-only)
~ Property Active Des i gnF i l e As Design File (read-
onl y )
~ Property ActiveModelRefe r ence As
Mode l Refere nce {read-on l y}
~ Property ActiveSettings As Set t ing s {r ead-
onl y }
~ Property Act i veWorkspace As Workspace {read-
on l y}
~ Sub AddAttachmentEventsHandler(EventHandler As
IAttachm ent Event s)
~ Sub AddChangeTrackEventsHandler(EventHandler
As IChangeTrackEvents)
~ Sub AddLeve l Cha ng eEven t sHandler(Event Hand l er
As ILevelChangeEvents)
~ Sub AddModalDialogEventsHandler(EventHandler
As IModalDialogEvents)
~ Sub AddModelActivateEventsHandler(EventHandler
As IModelActivateEvents)
~ Sub AddModelChangeEventsHandler(EventHandler
As IMode l ChangeEvents)
~ Sub AddSaveAsEventsHand l er(EventsHandler As
ISaveAsEvents)
~ Sub AddV i ew UpdateEventsHand l er(EventHandler As
IV ie wUp dat e Ev ents)
~ Sub Appe ndXDatum(X Data() As XDatum, Type As
MsdXDatumType, Value As Var i ant)
~ Functio n
Ap~ l y H orizontalScal i ngF i xForEM F (P i xelCo o rdi n at
e As Doub l e) As Long
~ Funct i on
ApplyVerticalSca li ngF i xForE MF(P i xe l Co ordinate
As Double) As Long
~ Funct i on
AssembleComplexStr i ngsAndShapes(Cha i nableEleme
nt s () As ChainableElement, [GapTo l er ance As
Double = - lJ ) As Ele men t Enu me ra tor
I The MicroStation Object Model I 195
~ Fun ction
Point 3d Fr omSeg ment3dFra ct io nParameter(S egm ent
As Segment3d , Fracti on As Double) As Point3d
~ Function Point3dFromSegment3dTangent(Segment
As Segment3d) As Point3d
~ Function Point3dFromTransform3d(Transform As
Transform3d) As Point3d
~ Function
Point3dFromTransform3dTimesPoint3d(Transform
As Transform3d, Point As Point3d) As Point3d
~ Function
Po i nt3dFromTransform3d TimesXYZ(Transform As
Tr ansform3d, X As Do ubl e, Y As Double, Z As
Do uble) As Point3d
~ Function Point3dFromVector3d(Vector As
Vector3d) As Point3d
~ Function Point3dFromXY(Ax As Double, Ay As
Double) As Point3d
~ Function Point3dFromXYZ(Ax As Double, Ay As
Double, Az As Double) As Poin t 3d
~ Function Point3dGetComponent(Point As Po i nt3d,
Index As Long) As Double
~ Function Point3dInPolygonXY(Point As Point3d,
Po l ygonVertices() As Point3d, [Tolerance As
Doub l e = -1J) As Long
~ Function Point3dInterpolate( PointO As Point3d,
FractionParameter As Double, Point1 As Point3d)
As Point3d
~ Function Point3d IsPointInCCWSector(TestPoint
As Poin t3d, Or i gin As Poi nt3d, Ta rgetO As
Point3d, Target 1 As Point3d, UpVector As
Point3d) As Boolean
~ Fun ct i on
Point3dIsPointInSmallerSector(TestPo i nt As
Point3d, Origin As Point3d, Target1 As Point3d,
Target2 As Point3d) As Boolean
~ Function Point3dIsVectorInCCWSector(TestVector
As Point3d, VectorO As Po i nt3d, Vector1 As
Point3d, UpVector As Point3d) As Boolean
~ Function
Po i nt3dIsVectorInSmallerSector(TestVector As
210 I Chapter 11: The MicroStation Object Model- Objects I
Po in t3 d, Vecto r O As Point3d , Vecto r l As
Po i nt3d) As Boo l ean
~ Function Point3dMagnitude(Vector As Point3d)
As Doub l e
~ Function Point3dMagnitudeSquared(Vector As
Point3d) As Double
~ Function Point3dMaxAbs(Vector As Point3d) As
Double
~ Function Point3dNegate(Vector As Point3d) As
Point3d
~ unction Point3dNormalize(Vector As Point3d) As
Point3d
~ Function Point3dOne() As Point3d
~ Function
Point3dPlanarAngleBetweenVectors(Vectorl As
Point3d, Vector2 As Point3d, PlaneNormal As
Point3d) As Double
~ Function Po int 3dPolarAngle(Vector As Point3d)
As Double
~ Function Point3dProjectToPlane3d(Point As
Point3d, Plane As Plane3d, [ViewSpecifier As
Variant], [ UseAuxil i aryCoordinateSystem As
Boo l ean = False]) As Point3d
~ Funct i on Point3dProjectToRay3d(Paramete r As
Doub l e, Point As Point3d, Ray As Ray3d,
[Vi ewSpecif i e r As Va r i ant],
[UseAuxiliaryCoordinateSystem As Boolean
False]) As Point3d
~ Function Point3dRotateXY(Vector As Point3d,
Theta As Double) As Point3d
~ Function Point3dSca l e(Vector As Point3d, Scale
As Doub l e) As Point3d
~ Sub POint3dSetComponent(Point As Point3d,
Index As Long, Value As Double)
~ Funct i on
Point3dSignedAngleBetweenVectors(Vectorl As
Point3d, Vector2 As Point3d, OrientationVector
As Point3d) As Double
~ Function
POint3dSmallerAngleBetweenUnorientedVectors(Ve
ctorl As Point3d, Vector2 As Point3d) As Double
I The MicroStation Object Modell 211
[B Function
POint 3dSm al l e r AngleB etw ee nUn ori ent edV ecto r sX Y(
Vector l As Po i nt3d, Vector2 As Po i nt3 d ) As
Double
[B Function Point3dSubtract(Pointl As Point3d,
Point2 As Point3d) As Point3d
[B Functi on Point3dSubtractPoint3dVector3d(Base
As Point3d, Vector As Vector3d) As Point3d
[B Function Point3dTripleProduct(Vectorl As
Point3d, Vector2 As Point3d, Vector3 As
Point3d) As Doub l e
[B Function PO i nt3dTripleProduct4Points(Origin As
Po in t3d, Ta r getl As Po i nt3d, Target2 As
Poi nt3d, Target3 As Po i nt3d) As Doub l e
[B Fun ction Point 3dZero() As Point 3d
[B Funct i on PointsToPixelsX(PointCoordinate As
Double) As Long
[B Function PointsToPixelsY(PointCoordinate As
Double) As Long
[B Property ProcessID As Long {read-only}
[B Sub Quit()
[B Function Radians(Degrees As Double) As Double
[B Function Range3dContainsPoint3d(Range As
Range3d, Point As Point3d) As Boolean
[B Function Range3dContainsXYZ(Range As Range3d,
X As Doub l e, Y As Double, Z As Double) As
Boolean
[B Funct i on Range3dEqua l (Rangel As Range3d,
Range2 As Range3d) As Boolean
[B Function Range3dE qua l To l erance(RangeO As
Range3d, Rangel As Range3d , Tolerance As
Doub l e) As Boolean
[B Funct i on Range3 dEx t entSq uare d(Range As
Range3d) As Double
[B Functio n Range3dFromPoint3d(Point As Point3d)
As Range3d
[B Funct i on Range3dFromPoint3d Point3d(PointO As
Point3d , Po i ntl As Point3d) As Range3d
[B Funct i on
Range3dFromPoint3dPoint3dPoint3d(PointO As
212 I Chapter 11: The MicroStation Object Model- Objects I
Point 3d, Pointl As Point3d, Point2 As Poi nt3d)
As Range3d
~ Function Range3dFromRange3dMargin(Range As
Range3d, Margin As Double) As Range3d
~ Function Range3dFromXYZ(X As Double, Y As
Doub le, Z As Double) As Range3d
~ Function Range3dFromXYZXYZ(Xl As Double, YI As
Double, Zl As Double, X2 As Double, Y2 As
Double, Z2 As Double) As Range3d
~ Func tio n Range3dlnitC) As Range3d
~ Function Range3dlntersect(Rangel As Range3d,
Range2 As Range3d) As Range3d
~ Function Range3dlntersect2(ResultRange As
Range3d, Rangel As Range3d, Range2 As Range3d)
As Boolean
~ Function
Range3dlsContainedlnRange3d(InnerRange As
Range 3d, OuterRange As Range3 d ) As Boolean
~ Function Range3dlsNull (Range As Range3d) As
Boolean
~ Function Range3dScaleAboutCenter(Rangeln As
Range3d, Scale As Double) As Range3d
~ Function Range3d Union(R angeO As Range3d,
Rangel As Range3d) As Range3d
~ Function Range3dUnionPoi nt3d(Range As Range3d,
Point As Point3d) As Range3d
~ Function Range3dUnionXYZ(Range As Range3d, X As
Double, Y As Double, Z As Double) As Range3d
~ Property RasterManager As RasterManager
(read-only)
~ Sub Ray3dClosestPoint(Ray As Ray3d, SpacePoint
As Point3d, ClosePoint As Point3d,
CloseFraction As Double)
~ Sub Ray3dClosestPointBounded(Ray As Ray3d,
SpacePoint As Point 3d, ClosePoint As Point3d,
CloseFraction As Double)
~ Sub Ray3dClosestPointBoundedXY(Ray As Ray3d,
SpacePoint As Point3d, ClosePoint As Point3d,
CloseFraction As Double)
IThe MicroStation Object Modell 213
~ Function Transform3dEqualTolerance(Transforml
As Transform3d, Transform2 As Transform3d,
Matrix Tolerance As Dou ble, Point Tol era nce As
Do ubl e) As Boo l ea n
~ Fun ction Transform3dFactorMirror(Transform As
Transform3d, ResidualTransform As Transfor m3d,
Mirror Transform As Transform3d, Fi xedPo i nt As
Poi nt 3d, Pl ane Norma l As Poi nt3d) As Boo l ean
~ Function Transform3dFromLi neAndRotation
Angle(PointO As Point3d, Pointl As Point3d,
Radians As Double) As Transform3d
~ Function Transform3dFromMatrix3d(Mat r ix As
Matrix3d) As Trans f orm3d
~ Function
Transform3dFromMatrix3dAndFixedPoint3d(Matrix
As Matrix3d, Origin As Point3d) As Transform3d
~ Function Transform3dFromMatr i x3dPoint3d(Matrix
As Matrix3d, Translation As Point3d) As
Transform3d
~ Function Transform3dFromMatrix3d
TimesTransform3d(Matrix As Matrix3d, Transform
As Transform3d) As Tran sform3d
~ Function Tra nsfor m3dFromMirrorPlane (O rigin As
Point3d, Normal As Point3d) As Transform3d
~ Function Transform3dFromPlane3dToWorld(Plane
As Plane3d) As Transform3d
~ Fu nc ti on Tran s form3dFromPo i nt 3d(Tran s la t ion As
Point3d) As Transform3d
~ Function Transform3dFromRowValues(XOO As
Double, XOI As Double, X02 As Double, Tx As
Double, XIO As Double, XII As Double, Xl2 As
Double, Ty As Double, X20 As Double, X21 As
Double, X22 As Double, Tz As Double) As
Tr ansform3d
~ Function
Transf orm3dFromSqu a redTran s form3d(Tran sf orm As
Transform3d, Pr i maryAxis As Long,
Secunda ['yAx is As Long) As Trans form3d
~ Function
Transform3dFromTra nsform3dTimesMa t rix3d(T r an sf
orm As Transfo r m3d , Matri x As Ma tr i x3d) As
Tra nsfo rm 3d
I The MicroStation Object Modell 217
[B Function
Tra nsform3dFro mTransfor m3d TimesT ransform3d(Tra
nsforml As Transform3d, Transform2 As
Transform3d) As Transform3d
[B Function
Transform3dFromTransform3dTimesTransform3dTime
sTransform3d( Transfo rml As Transform3d,
Tra ns f or m2 As Tr ans f orm3 d , Tr ansform3 As
Tran s f or m3d) As Tr ansf or m3d
[B Fu nct i on Transfo r m3d From Wor l dToP l ane3d(Plane
As Pl ane3d) As Trans f orm3d
[B Function Transform3dFromXYZ(X As Double, Y As
Double, Z As Double) As Transform3d
[B Function
Transform3dGetMatrixComponentByRowAndCo l umn(Tr
ansform As Transform3d, Row As Long, Col As
Long) As Double
[B Function
Transform3dGetPointComponent(Transform As
Transform3d, Row As Lo ng) As Double
[B Function Transform3dHaslnverse(Transform As
Transform3d) As Boolean
[B Function Transform3dldentity() As Transform3d
[B Function Tra nsform3dl nverse(In As Transform3d)
As Transform3d
[B Function Transform3dIsldentity(Transform As
Transform3d) As Boole an
[B Function
Transform3dIsMirrorAboutPlane(Transform As
Transform3d, Pl anePoint As Point3d,
Pl aneNormal As Point3d) As Boolean
[B Function Trans f orm3dIsPlanar (Transform As
Transform3d, Normal As Point3d) As Boolean
[B Function Transform3dIsRigid(Transform As
Transform3d) As Boolean
[B Function
Transform3dIsRotateAroundLine (Transform As
Transform3d, Fi xedPoint As Point3d,
Directi onVector As Point 3d, Rad i ans As Double )
As Boolean
218 I Chapter 11: The MicroStation Object Model - Objects I
~ Fun ction Tran s fo rm3dlsTranslate CTr ans form As
Tran sf orm3d, Tr ans l at i on As Poin t3 d ) As Boo l ean
~ Function
Transform3dlsTranslateRotateScaleRotateCTransf
orm As Transform3d, Translation As Point3d,
Rotat i onl As Mat r i x3d , ScaleFactors As Po int 3d,
Rotation2 As Ma trix3d) As Boolean
~ Function Transform3dlsUniformScaleCTransform
As Transform3d, FixedPoint As Point3d , Scale As
Double) As Boolean
~ Fu nct i on
Tra nsform3 dl sU ni formSca l eA ndRotateAro undL i neCT
ransform As Transform3 d , Fi xed Point As Poi nt3d,
Direc ti on Vector As Po i nt3d, Rad i ans As Doub l e,
Scale As Double) As Boolean
~ Sub
Transform3dSetMatrixComponentByRowAndColumnCTr
ansform As Transform3d, Rowlndex As Long,
Co lumnlnde x As Long, Value As Double)
~ Sub Transform3dSetPointComponentCTransform As
Transform3d, Rowlndex As Long, Value As Doub l e)
~ Function Transfor m3dZeroC) As Transform3d
~ Function UpdateGraphicGroupNumberC) As Long
~ Property UserNam e As Str ing {read-only}
~ Property VBE As Object (r ead-on l y )
~ Function Vector3dAddCVectorl As Vector3d,
Vector2 As Vector3d) As Vector3d
~ Funct i on Vector3dAdd2Sca l edCOrig i n As
Vector3d, Vectorl As Vecto r 3d, Scalel As
Do uble, Vec t or2 As Vec t or 3d, Sca l e2 As Double)
As Vec t or3d
~ Function Vector3dAdd3Sca l edCO r igin As
Vec t or 3d, Vecto r l As Vec t or 3d , Sca l el As
Doub l e, Vector2 As Vector3d, Scale2 As Doub l e,
Vector3 As Vector3d , Scale3 As Doub l e) As
Vector3d
~ Funct i on Vector3dAddScaledCOr i gin As Vector3d,
Vector As Vector3d, Scale As Do uble) As
Vector3d
IThe MicroStation Object Modell 219
ApplicationObjectConnector
~ Pro per t y Application As Application {read -
on1y}
Attachment
~ Sub Act iv at e ()
I The MicroStation Object Modell 223
Attachments
~ Fu nct i on Add( Fi l eS pec if icat i on As St r i ng,
Mode l Name As String, LogicalName As String,
Description As String, MasterOrigin As Point3d,
ReferenceOr i gin As Point3d, [ TrueScale As
Boo l ean = True], [D i splayImmed i ately As Boolean
= True ] ) As At t ac hme nt
~ Functi on AddCoi nc ident(FileSpe c ifi cati on As
Str i ng, ModelN ame As String, Lo gi calName As
St r i ng, Descr i ption As String,
[Disp l ay Immediately As Boo l ean = True ] ) As
At tachment
~ Fu nction AddCoinc i dentl(FileSpecif i cation As
String, ModelName As Str i ng, Logical Name As
String, Des cri ption As St ring, Fl ags As
MsdAddAttac hm ent Fla gs) As Attachment
~ Function AddUs i ngNamedView(FileSpecification
As String, LogicalName As String, Description
As String, ViewName As String, CenterPo i nt As
Point3d, [DisplayImmediately As Boolean =
True]) As Attachment
~ Function AddUsingNamedViewl(F i leSpecification
As String, ModelNa me As String, Logica l Name As
String, Description As String, ViewName As
String, CenterPoint As Point3d, Flags As
MsdAddAttachmentFlags) As Attachment
~ Property Count As Long {read- only}
~ Function FindByLogicalName(LogicalName As
String) As Attachment
~ Property Item As Attachment {read-only}
~ Sub Remove(AttachmentSpecif i er As Variant)
Cad lnputMessage
~ Pr operty CommandKey in As St r i ng {read-on l y}
~ Property CursorButton As Long {read-only}
~ Property I nputType As MsdCadInputType {read-
only}
~ Property Keyin As String {read-only}
~ Property Point As Point3d {read-only}
~ Property ScreenPoint As Point3d {read-only}
~ Property View As View {read-only}
228 I Chapter 11: The MicroStation Object Model - Objects I
[B CadlnputQu eue
[B Function Get l np ut ( [Type l As MsdCa dln putType =
msdCadlnputTypeAnyJ. [Type2 As
MsdCadlnputTypeJ. [Type3 As MsdCadlnputTypeJ.
[Type4 As MsdCadlnputTypeJ) As CadlnputMessage
[B Sub Se ndCommand (Co mm an d As St ri ng .
[ Tr eatLikeKeyboardlnput As Bo olean J)
[B Sub SendDataPoint(Da t aPoint As Point 3d.
[Vi ewSpec i f i er As Varia nt J . [Q ualifi er As
LongJ)
[B Sub Sen dD at aPo intF orLocate( El eme nt ToLocate As
El ement. DataPo i nt As Poin t3d. [ViewSpecif i er
As Var i antJ. [Qual ifier As LongJ)
[B Sub SendDragPoin t s(DownPoint As Po i nt 3d .
UpPoint As Point3d. [ViewSpecifier As VariantJ.
[Qual ifie r As LongJ)
[B Sub SendKey in(Keyin As String)
[B Sub SendLast lnput()
[B Sub Sen dM essage To Appl i cationCMd l App li cation As
Str in g. Message As String)
[B Sub SendResetC)
[B Sub SendTentativePointCDataPoint As Po int 3d .
ViewSpeci f i er As Varia nt)
OesignFile
[B Fu nc ti on Ad dN ew Leve l CLevelN ame As Str in g) As
Level
[B Sub Attac hCo l orTab l eCCo l orTable As ColorTab l e)
[B Prope r ty Aut hor As String
[B Prope r ty Clie nt As Stri ng
[B Sub Cl oseC)
[B Proper t y Co mm en t s As St ri ng
[B Property Co mpany As Stri ng
[B Funct i on CustomPropertyEx i stsCNa me As Str i ng)
As Boo l ean
[B Property DateC r eated As Date {read-on l y}
[B Property DateLastP l otted As Date {read-only}
[B Property DateLastSaved As Date {read-only}
I The MicroStation Object Modell 229
Element
~ Sub AddDatabaseLink(LinkToAdd As DatabaseLink)
~ Function AddTag(TagDefinition As
TagDefinition) As TagElement
~ Function Add Tags(TagSet As TagSet) As
TagElement()
~ Sub AddUserAttributeData(AttributeID As Long.
AttributeData As DataBlock )
~ Funct i on ApparentColor(View As View) As Long
~ Function ApparentLineStyle(View As View) As
Lin eStyle
~ Function ApparentLineWe i ght(View As View) As
Long
~ Property AsApplicationElement As
ApplicationElement (read-only)
~ Property AsArcE l ement As ArcElement (read-
only)
~ Property AsAuxiliaryCoordinateSystemElement As
AuxiliaryCoordinateSystemElement (read-only)
I The MicroStation Object Modell 231
ElementEnumerator
~ Function BuildArrayFromContent s () As Ele me nt ( )
ElementScanCriteria
~ Sub Excl udeAll Cl asses()
level
~ Sub AddUserAttributeData(Attr i buteID As Long,
AttributeData As DataBlock)
238 I Chapter 11: The MicroStation Object Model - Objects I
~ Function Del eteUse r At tributeDa ta(Attr ibut e ID
As Long, Ind ex As Integer) As Intege r
~ Property Description As String
~ Property ElementAccess As
Msd LevelElementAccess
~ Property ElementColor As Long
~ Property ElementLineStyle As Li neStyle
~ Property ElementLineWeight As Long
~ Function GetUserAttributeData(AttributeID As
Long) As DataBlock()
~ Property 10 As Long {read-only)
~ Property 1sActive As Boolean
~ Property IsDisplayed As Boo l ean
~ Property IsDisplayedlnView As Boolean
~ Property I sEffective l yDisp l ayed lnVi ew As
Bo ol ean {read-only)
~ Property I sFrom LevelLibrary As Boo l ean {read-
only)
~ Property IsFrozen As Boolean
~ Property Is1nUse As Boolean {read -only)
~ Function IsInUseWithinModel(Model As
ModelReference) As Boolea n
~ Property 1sLocked As Boolean
~ Property Name As String
~ Property Number As Long
~ Property OverrideCo l or As Long
~ Property OverrideLineStyle As LineStyle
~ Property OverrideLineWeight As Long
~ Property ParentLevel As Level
~ Property Plot As Boolean
~ Property UsingOverrideColor As Boolean
~ Property UsingOverrideLineStyle As Boolean
~ Property UsingOverrideLineWeight As Boolean
ModelReference
~ Sub Activate()
REVI EW
We have just displayed a fraction of the Objects available to us in
MicroStation. At times it is useful to see a listing (even a partial listing)
and browse through the items in it.
The Object Browser in VBA is especially helpful when attempting to get
a grasp on the Object Model of any Library. VBA includes other tools as
well that can aid in our development efforts. These include adding
Watches and the AutoList functionality.
242 I Chapter 11: The MicroStation Object Model- Objects I
12 The MicroStation Object
Model - Enums
MSDDESIGNFILEFoRMAT
msdDesign FileFormatCurrent 0
msdDesignFileFormatDWG = 3
msdDesignFileFormatDXF = 4
msdDesignFileFormatUnknown -1
msdDesignFileFormatV7 1
msdDesignFileFormatV8 2
The enumeration name is "MsdDesignFileFormat". It has six members
with values ranging from -1 to 4. Each member in an enumeration has a
name and a value. The enumeration member
"msdDesignFileFormatCurrent" has a value of O. As we saw in the
previous chapter, some properties and methods make use of these
enumerations. For example,
243
244 I Chapter 12: The Mi croStation Object Model - Enums I
Sub SaveAs(New FileName As St ri ng. [Overwr it e As _
Boo l ean = False]. [NewFormat As MsdDes i gnFileFormat _
= msdDesignFileFormatCurrent])
The SaveAs method is found under the DesignFile object. When we use
it, we can specify a file name, whether an existing file should be over-
written, and the file format to be used. The data type for
"NewFileName" is String. The value type for "Overwrite" is Boolean.
The value type for "NewFormat" is MsdDesignFileFormat. The
"NewFormat" parameter utilizes the "MsdDesignFileFormat"
enumeration. As we use the SaveAs method, we see the following:
ActiveDesignFile.SaveAs "test.dgn", TrUe,
SaveAs(NewFiIeNameA"Stni?Q,IOYelwl1 CD ~~!2!I£.i~~atcur~~ _ _- sdOesi nFileFormut - msdOes! IlFileFormlltCurrent )
CD msdDesignFHeFormatDWO
III msdOesignFileFormalDXF
!II mSdDesignFlieFormatUnknown
!II msdDeslgnFileFormal'l7
CD msdDesignFlleFo rmatvS
MsdACSType
msdACSTypeCyl i nd r ical 2
msdACS TypeNone = 0
msdACSTypeRectangu l ar 1
msdACSTypeSpherica l = 3
MsdAddAttachmentFlags
msdAddAttachmentElementsVisible = 4
msdAddAttachmentFlagCoincidentWorld 2
msdAddAttachmentFlagNone = 0
msdAddAttachmentFlagTrueScale 1
MsdAngleAccuracy
msdAngleAccuracyO 0
msdAngleAccuracyl 1
msdAngleAccuracy2 2
msdAngleAccurac y3 3
msdAngleAccuracy4 4
msdAng l eAccuracy5 5
msdAngleAccuracy6 6
msdAngleAccuracy7 7
msdAngleAccuracy8 8
MsdAngleFormat
msdFormatDD_DDDD = 0
msdFormatDD MM SS = 1
msdFormatGradians = 2
msdFormatRadians = 3
246 I Chapter 12: The MicroStation Object Model - Enums I
MsdAngleMode
msdAngleModeAzimuth = 1
msdAngleModeBearing = 2
msdAngleModeConventional 0
MsdAttachMode
msdAttachNone = 1
msdAttachReference = 3
MsdBsplineCurveOffsetCuspType
msdBsp l ineCurveOffsetCuspArc = 4
msdBsplineCurveOffsetCuspChamfer = 1
msdB s pl i neC urveO f fsetCus pJ ump = 0
msdBsp li neCurveOffsetCuspParabo la = 3
msdBsplineCurveOffsetCuspPoint = 2
MsdBsplineCurveType
msdBsplineCurveCircle = 3
msdBsplineCurveC i rcu l arArc 2
msdBsplineCurveEllipse = 5
msdBsplineCurveEllipticalArc 4
msdBsplineCurveGeneral = 0
msdBsplineCurveHyperbolicArc = 7
msdB s pline CurveLin e = 1
msdBsplineCurveParabolicArc = 6
MsdBsplineParametrizationType
msdBsp l ineParame t r i zat i onCentripeta l 2
msdBsplineParametrizatio nChordLength 1
msdBsplineParametrizationInher i ted 3
msdBsplineParametrizatio nUniform 0
MsdBsplineSurfaceDirection
msdBsp l ineSurfaceU 0
msdBsplineSurfaceV = 1
Msd BsplineSurfaceType
msdBsplineSurfaceCone = 3
msdBsplineSurfaceGeneral = 0
I The Enumeration List I 247
MsdCadlnputType
msdCadInputTypeAny = 5
msdCadInputTypeCommand 1
msdCadInputTypeDataPoint 3
msdCadInputTypeKeyin = 4
msdCadInputTypeReset = 2
msdCadInputTypeUnassignedCB 6
MsdCeliType
msdCellTypeGraphic 0
msdCe l lTypeMenu = 1
msdCel l TypePoint = 7
MsdChangePropagation
msdChangePropagationA l ways = 2
msdChangePropagationGroupL ock 0
msdChangePropagationNever 1
MsdChangeTrackAction
msdChangeTrackActionAdd 2
msdCha ngeTrackActionAppData = 8
msdChangeTrackActionDelete 1
msdChangeTrackAct i onDrop = 6
msdChangeTrackActionMark = 7
msdChangeTrackActionModelAdd = 9
msdChangeTrackActionModelDelete 10
msdChangeTrackActionModify = 3
msdChangeTrackActionModifyFence = 5
msdChangeTrackActionNewF il ePositionAndMod ify 4
248 I Chapter 12: The MicroStation Object Model - Enums I
MsdCommandResult
msdCommandResult3dL i brary2dF il e 50
msdCommandResult3dOnly = 39
msdCo mmandResultAcceptOuery 68
msdCo mm andResultBadCellName 47
msd Comm an dRe s ult Ce ll Del et ed 59
msdCom ma ndRe s ult CellE xi sts = 55
msdCo mmandResultCe ll Li braryNot Found 12
msdCommandResultCellNestingError = 43
msdCommandResu l tCe llN ot Found = 44
msdCommandResultElementNotFound = 21
msdCommandResultEmptyFence = 27
msdCommandResultFileReadOnly = 287
msdCommandResultIllegalDefinition = 23
msdCommandResultlnvalidReferenceOperation 481
msdCommandResultNeedCharacters = 27
msdCommandResultNoActiveCell = 19
msdCommandResultNoCellLibrary 54
msdCommandResultNoFenceActive = 15
msdCommandResultNoOrigin = 56
msdCommandResultOffDesignPlane = 22
msdCommandResultReferenceNotFound = 7
ms dCommandResultSuccess = 0
msdCommandResultUnknownCommand = 16
msdCommandResultViewNotFound 18
MsdConversionMode
msdConversionModeAlways = 1
msdConversionModeNever = 0
msdConversionModePrompt = 2
MsdCoordinateAccuracy
msdAccuracyO = 1
msdAccuracyl = 2
msdAccuracy16th = 56
msdAccuracy2 3
msdAccuracy3 = 4
I The Enumeration List I 249
msdAccuracy32nd = 120
msdAccuracy4 = 5
msdAccuracy4th 8
ms dAccuracy5 = 6
msd Accu r acy6 = 7
msd Acc ura cy6 4t h = 248
msdAcc ura cy 8th = 24
msdAcc ur acy Hal f = 0
MsdCoordinateFormat
msdMasterUnits = 1
msdSubUnits = 0
msdWorkingUnits = 2
MsdCopyContextLevelOption
msdCopyContextLevelAlreadyRemapped = 4
msdCopyContextLevelByUserPreference = 0
msdCopyContextLevelCopyAlways = 3
msdCopyContextLevelCopylfD i fferent = 2
msdCopyContextLevelCopylfNotFound = 1
MsdCopyViewPort
msdCopyViewPortApplyAspectRatio = 2
msdCopyV iewPortApp lySize = 3
msdCopyViewPortApplySizeAndPosition 4
msdCopyViewPortKeepCurrent = 0
MsdDatabaseLinkage
msdDatabaseLinkagelnformix = 1
msdDatabase Linkagelngres = 32
msdDatabaseLinkageOdbc = 128
msdDatabaseLinkageOleDb = 256
msdDatabaseL i nkageOracle = 8
msdDatabaseLinkageXBase = 4
MsdDataEntryRegionJustification
msdDataEntryRegionJustificat i onCenter = 0
msdDataEntryRegionJustificationLeft = -1
msdDataEntryRegionJusti f icationRight = 1
250 I Chapter 12: The MicroStation Object Model - Enums I
MsdDevelopableElementOutputType
msdDeve1opab1eCones = 4
msdDeve1opab1eConesP1anar = 5
msdDeve1opab1eRu 1eLines = 0
msdDeve1opab1eRu 1eLine s P1anar 1
msdDeve1opab1eShapes = 2
msdDeve1opab1eShap esPlanar 3
MsdDimAccuracy
msdDimAccuracyO = 0
msdDimAccuracy1 = 129
msdDimAccuracy16th = 8
msdDimAccuracy2 = 130
msdDimAccuracy3 = 132
msdDimAccuracy32nd = 16
msdDimAccuracy4 = 136
msdDimAccuracy4th = 2
IThe Enumeration List I 251
msdDimAccuracy5 = 144
msdDimAccuracy6 = 160
msdD i mAccuracy64th = 32
ms dDim Accur acy7 = 192
msdDimAccuracy8 = 128
msdDimAccuracy8th = 4
msdDimAccuracyHalf 1
msdDimAccuracyScil 64
msdDimAccuracySci2 65
msdDimAccuracySci3 66
msdDimAccuracySci4 67
msdDimAccuracySci5 68
ms dDim Acc uracySc i 6 69
msdDim Accura cySci7 70
msdDim Acc ur acySc i 8 71
MsdOimAlignment
msdDim Alig nme nt Ar bitr a ry 3
msdD i mAl i gnm ent Dr awin g = 1
msdDi mA lignm ent Tru e 2
msdDimAlignmentView = 0
MsdOimAlternateThresholdComparison
MsdD i mAlter nat eT hres hol dCo mpar i sonGreater = 1
MsdDimAlternateThr esho ldC omparisonGreaterOrEqual = 3
MsdDimAlternateThresholdComparisonLess = 0
MsdDimAlternateThresholdComparisonLessOrEqual = 2
MsdOimBaliAndChainAlignment
msdDimBallAndChainAlignmentAuto 0
msdDimBallAndChainAlignmentLeft 1
msdDimBallAndChainAlignmentRight = 2
252 I Chapter 12: The MicroStation Object Model - Enums I
MsdDimBallAndChainChainType
msdD i mBal l AndC hai nC hain TypeA r c = 2
msdDimBallAndChainChainTypeBSpline 3
msdDimBallAndChainChainTypeLine 1
msdDimBallAndChainChainTypeNone 0
MsdDimCustomSymbol
msdDimCustomSymbolCharacter 1
msdDimCusto mSym bolDefault 0
MsdDimDMSPrecisionMode
MsdDimDMSPrecisionModeFixed = 0
Msd Di mDM SPrecisionModeFloa t ing 1
MsdDimLabelLineFormat
MsdDim LabelLine FormatAngleAbove = 3
MsdDi mLabe lL ine FormatA ngl eBe l ow = 5
MsdDimLabe lL ineForma t Angl eOver Lengt h = 1
MsdD i mLabe lL ine Forma tL engt hAbove = 2
MsdD i mLabe lL ineFor matLengthAng l eAbove 6
Ms dDi mLabe lLin eFor mat Lengt hAngl eBe l ow 7
MsdD im Labe lLin eFor mat LengthBelow = 4
MsdD i mLabe lLi neFor matS t andard = 0
MsdDimMLNoteFrameType
msdDimM LNoteFrameTypeBox = 2
msdDimMLNoteFrameTypeLine 1
msdDimM LNoteFrameTypeNone = 0
MsdDimMLNoteJustification
msdDimMLNoteJustificationCenter = 3
msdDimMLNoteJustificationDynamic = 2
msdDimMLNoteJustificationLeft = 0
msdDimMLNoteJustificationRight = 1
MsdDimNoteHorizontalAttachment
msdDimNoteHorizontalAttachmentAuto 0
msdDimNoteHorizontalAttachmentLeft 1
IThe Enumeration List I 253
msdDimNoteHor iz ontalAttachmentRight 2
MsdDimNoteLeaderType
MsdDimNoteLeaderTypeCurve = 1
MsdDimNoteLeaderTypeLine = 0
MsdDimNoteTextRotation
msdDimNoteTextRotationHorizontal 0
msdDimNoteTextRotationlnline = 2
msdDimNoteTextRotationVertical 1
MsdDimNoteVerticalAttachment
msdDimNoteVerticalAttachmentBottom = 4
msdD i mNoteVert i calAttachmentBottom Lin e = 3
msdDimNoteVerticalAttachmentDynamicCorner 6
msdDimNoteVerticalAttachmentDynamic Line = 5
msdDimNoteVerticalAttachmentMidd le = 2
msdDimNoteVerticalAttachmentTop = 0
msd DimNoteVerticalAttachmentTopLine = 1
msdDimNoteVerticalAttachmentUnderline 7
MsdDimNoteVerticalJustification
msdDimNoteVerticalJustificationBottom 2
msdDimNoteVerticalJustificationCenter 1
msdD im NoteVert i calJust i f i cat ionDynam i c = 3
msdDimNoteVerticalJustification Top = 0
MsdDimPlacementTextPosition
msdDimPlacementTextPosit i onAuto = 2
msdDimPlacementTextPositionManual = 0
msdD imPl acementTextPositionSemiAuto 1
MsdDimRadialMode
msdDimRadialModeCenterMark = 0
msdDimRadialModeDiame te r = 3
msdDimRadialModeDiameterExtended 4
msdD i mRadialModeRadius = 1
msdDimRadialModeRadiusExtended 2
254 I Chapter 12: The MicroStation Object Model - Enums I
MsdDimStackedFractionAlignment
Ms dDi mSt ac kedFractionAlignmentBottom 2
MsdOimStackedFractionAlignmentCenter 1
MsdO i mStacked FractionAl i gnment Top = 0
MsdDimStackedFractionType
MsdOimStackedFractionTypeOiagon al 2
Msd Oim St ac kedFra ct i on Type Fr omF ont 0
MsdOimStackedFractionTypeHorizontal 1
MsdDimStyleProp
msdO im Sty l ePropBallAndChai nAl ignment = 101
msdOimStylePropBallAndChainChainTerminator 102
msdOimStylePropBallAndChainChainType = 103
msdDimSty l ePropBallAndChainIsActive = 104
msdOimStylePropBallAndChainNoOockOnDimLine = 106
msdOimSty l ePropBal l AndChainShowText Leader = 105
msdOimStylePropE xtensionLineAngleChordAlign = 213
msdO im StylePropExtens i onLineColor = 201
msdOimStylePropExtensionLineExtend = 202
msdDimStylePropExtensionLineJoin = 203
msdOimStylePropExtensionLineLeft = 204
msdOimStylePropExtensionLineLineStyle = 205
msdOimSty l ePropExtensionLineOffset = 206
msdOimSty l ePropExtens i onLineOverrideColor = 207
msdOimStylePropExtens i onLineOverrideLineStyle = 208
msdO i mSty l ePropExtens i onLineOve rrid eWeig ht = 209
msdOimStylePropExtensionLineRight = 210
msdOimStylePropExtensionLineShowAny = 211
msdOimStylePropExtensionLineWeight = 212
msdOimStylePropGeneralAlignment = 301
msdOimStylePropGeneralCenterMarkSize 302
msdDimStylePropGeneralColor = 303
msdOimStylePropGeneralOimensionScale = 304
msdOimSty l ePropGeneralOimStyleOescription 305
msdOimStylePropGeneralOimStyleName = 306
msdO i mStylePropGeneralFont = 30 7
IThe Enumeration List I 255
MsdDimSuperscriptMode
MsdD i mSupe r Scr i ptModeFrom Font = 0
MsdDimSup e rScr i pt ModeGenerated = 1
MsdDimSymbolType
msdD i mSymbo lTypeCel l = 2
msdDimSymbolTypeCharacter 1
msdD im Symbo l Type Def aul t = 0
MsdDimTerminatorArrowhead
msdDimTerminatorArrowheadClosed 1
msdDimTerminatorArrowheadFilled 2
msdDimTerminatorArrowheadOpen 0
MsdDimTerminatorMode
msdDimTerminatorModeAuto = 0
msdDimTerm i natorModelnside = 2
msdDimTerminatorModeOutside = 3
msdDimTerminatorModeReversed = 1
MsdDimTerminatorType
msdDimTerminatorTypeArrow 1
IThe Enumeration List I 261
msdOimTerminatorTypeCirc l e 3
msdOimTerminator TypeOot = 4
msdOimTerminatorTypeNone = 0
msdOimTerminatorTypeNote = 5
msd OimT erminatorTypeOrig in 3
msdOimTe rm inatorTypeStroke 2
MsdDimTextField
msdOimTextFieldLowerLimit 1
msdOimTextFieldMain = 0
msdOimTextFieldMinus = 2
msdOimTextFieldPlus = 1
msdOimTextFieldUpperLimit 0
MsdDimTextFormat
MsdOi mTex tForm atMU = 0
MsdOimT ex tFor mat MU dash SU = 4
MsdO i mT ex tF orm atMU_L abel = 1
Ms dOimTex tFor matMU Lab el das h SU Label 6
Ms dOi mText FormatMU_L ab el _S U_ Label = 5
MsdOimTe xtFormat SU = 2
Ms dOi mTex tF ormatSU_ Label = 3
MsdDimTextFrameType
MsdOimTextFrameTypeBox = 1
MsdOimTextFrameTypeCapsule 2
MsdOimTextFrameTypeNone = 0
MsdDimTexUustification
msdOimTextJustificationCenter = 2
msdOimTextJustificationLeft = 1
msdOimTextJustificationRight = 3
Msd Di mTextLocation
MsdOimTextLocationAbove = 1
MsdOimTextLocationInline = 0
MsdOimTextLocationOutside 2
MsdOimTextLocationTopLeft = 3
262 I Chapter 12: The MicroStation Object Model - Enums I
Msd Oi mTextOrientation
MsdDimTextOrientationA l igned = 0
MsdD i mTextOrientationHorizontal 1
MsdOimThousandsOpts
MsdDimThousandsOptsComma = 2
MsdDimThousandsOptsNone = 0
MsdDimThousandsOptsSpace = 1
MsdOimToleranceType
MsdDimToleranceTypeLimit = 1
MsdDimToleranceTypePlusMinus 0
MsdOimType
msd DimTypeA ng leAx i s = 10
msdD imTypeAngleAx i sX 50
msdDimTypeAngleAxisY = 51
msdDimTypeAngleLines = 9
msdDimTypeAngleLocation 7
msdDimTypeAngleSize = 5
msdDimTypeArcLocation 8
msdDimTypeArcS ize = 6
msdDimTypeCenter = 19
msdDimTypeC ustomLinear = 15
msdDimTypeDiameter = 12
msdDimTypeDiameterExtended = 18
msdDimTypeDiameterPara = 13
msdDimTypeDiameterPerp = 14
msdDimTypeLabelLine = 52
msdDimTypeLocateSingle = 3
msdDimTypeLocateStacked = 4
msdDimTypeNone = 0
msdDimTypeNote = 53
msdOi rnTypeOr'd i ria Le = 16
msdDimTypeRadius = 11
msdDimTypeRadiusExtended 17
msdDimTypeSizeArrow = 1
IThe Enumeration List I 263
msdDimTypeSizeStroke = 2
msdDimTypeUseActive = -1
MsdDimValueAngleFormat
msdDimValueAngleFormatCentesimal = 2
msdDimValueAngleFormatDegMinSec 1
msdD im ValueA ngleF orma tDe grees 0
msdDi mVal ueA ngl e For matRadi ans 3
MsdDimValueAnglePrecision
msdDimValueAnglePrecision1Place 1
msdDimVa l ueAnglePrecision2Place 2
msdDimValueAnglePrecision3Place 3
msdDimValueAnglePrecision4Place 4
msdDimVa l ueAnglePrecision5Place 5
msdDimValueAnglePrecision6Place 6
msdDimValueAnglePrecisionWhole = 0
MsdDimVerticalTextOptions
MsdDimVerticalTextOptionsAlways = 1
MsdDimVerticalTextOptionsNever 0
MsdDimVerticalTextOptionsNoFit = 2
MsdDrawingMode
msdDrawingModeErase = 1
msdDrawing ModeHi lit e = 2
msdD r awingModeNormal = 0
msdDrawingModeTemporary = 3
msdDrawingModeTemporaryErase 4
msdD r awingModeXor = 6
MsdElementCachePurpose
msdElementCachePurposeControl 2
msdElementCachePurposeGraph i cal 4
msdElementCachePurposeNonModel = 1
MsdElementClass
msdElementClassConstruction 2
264 I Chapter 12: The MicroStation Object Model - Enums I
ms dEl ement Cl assCon tru cti onRul e 6
msd El ementC l assOi mens i on = 3
msdElementClassLinearPatterned = 5
msdElementClassPatternComponent = 1
msd ElementClassPr im ary = 0
msd El eme ntC la ss Pri ma ryRu l e = 4
MsdElementSubtype
msdElementSubtypeApplicationElement = 20
ms dEl ement SubtypeA uxil iaryCoo r dinateSyste m 3
msdElementS ubtypeNone = - 1
msd ElementSubtype UpdateSeque nceE l ement 33
Msd ElementType
msdElementType44 = 44
msdE l ementTypeArc = 16
msdElementTypeBsplineBoundary 25
msdElementTypeBsplineCurve = 27
msdElementTypeBsplineKnot = 26
msdElementTypeBsp lin ePole = 21
msdElementTypeBsplineSurface = 24
msdElementTypeBsplineWeight = 28
msdElementTypeCellHeader = 2
msd El em entTyp eC ellLibraryHeader = 1
msdE l ementTypeComplexShape = 14
msdE l eme ntTypeCo mplexString = 12
ms dEl ementTypeC one = 23
msdE l ement TypeCon i c = 13
msdEleme ntTypeCurve = 11
msdE l ementType OesignFi l eHeader = 9
msd Eleme ntTypeOgnSto r eComponent = 38
msd Element Type OgnSto r eHeader = 39
msdElement Type Di gSetData = 8
msdElement TypeDimension = 33
msdElementTypeE l lipse = 15
msdElementTypeGroupData 5
msdElementTypeLevelMask = 99
IThe Enumeration List I 265
MsdError
msdAccuDrawNotEnabled = -2147218287
msdError3dReference2dMaster = -2147220767
msdErrorAccessVio la t i on = -2147218313
266 I Chapter 12: The MicroStation Object Model - Enums I
msdE r ro rAcs Not Fou nd = -2 14722 0744
msd Er r or AcsRep l aced = - 2147220745
msd Erro r AddressNotK nown = -2147220784
ms dErr or Addr es sN otValid = - 2147220779
msdE r rorAlreadyExi s ts = - 2147218310
msdErrorAlreadylnUse = -2147220804
msdErrorAlreadyOpen = -2147218312
msdErrorBadBSplineElement = -2147217996
msdErrorBadCharacterConstant = -2147220794
msdErrorBadConti nui ty = -2147217986
msdErrorBadElement = -2 147218399
msdErrorBadFi l e = -2147218304
msdErrorBadFloat = -2147220796
msdErrorBadFormat = -2147218309
msdErrorBadHexNumber = -2147220799
msdErrorBadlndex = -2147218370
msdErrorBadKnots = -2147217991
msdErrorBadLineWeights = -2147217990
msdErrorBadModelld = -2147218334
msdErrorBadModelReference = -2147218397
msdErrorBadName = -2147218316
msdErrorBadNumber = -2147220800
msdErro r BadOctal = - 2147 220797
msdErrorBadOrder = -2147217994
msdErrorBadParameter = -2147217995
msd Er ro r BadPer i od i city = -2 147217993
msdErrorBadPoles = -2147217992
msdErrorBadRasterFormat = -21472 18350
msdErrorBadReso urceType = -2147220772
msdErrorBadScanList = -2147218389
msdErrorBadSp i ra l Oef i nition = -2 147217989
msdErrorBadStr in g = -2147220795
msdErrorBadType = -2147220803
msdErrorBadVersion = -21472 18308
msdErrorBadWordsToFollow = -21472 18311
msdErrorCachelnUse = -2147218318
IThe Enumeration List I 267
MsdFileAccessMode
msdFileAccessMo deRead = 1
msdFileAccessModeReadWr i te 3
MsdFiIIMode
msdFil lMod eFi lled = 1
msdF illModeNot Fi lled = 0
msdFi l lModeOutl in ed = 2
msdFillModeU s eActive = -1
MsdFontType
msdFontTypeMicroStation 0
msd Fo nt TypeS HX = 1
msdFontTypeUnknown = 3
msdFont TypeWindow sTru eType 2
MsdGeoReferenceSisterFileType
msdGeoReferenceS i sterFileTypeHgr = 1
msdGeoReferenceSisterFileTypeNone = 0
msdGeoReferenceS i ster FileTypeTwf = 2
MsdGloba lLineStyleScale
msdGloba lL ineStyleScaleBoth 3
msdGloba l LineStyleScaleMaster 0
msdGloba l LineStyleScaleNone = 1
msdG l obalL i neSty l eScaleReference 2
MsdLevelChangeType
msdLevelChangeAfterChangeActive 9
272 I Chapter 12: The MicroStation Object Model - En ums I
msd LevelChangeA f terCreate = 2
msdLeve lChange Aft er Delet e = 3
msdLevelChangeBeforeChangeActive 17
msdLevelChangeBeforeDelete = 18
msdLevelChangeChangeAttribute 8
ms dLevelChangeChangeCode = 5
msdLevelChangeChangeDisplay = 7
msdLevelChangeChangeName = 4
msdLevelChangeChangeParent = 6
msdLevelChangeTableRedo 15
msdLevelChangeTableUndo = 14
MsdLevelElementAccess
msdLevelElementAccessAll = 0
msdLevelEl ementAccess Loc ked = 1
msdLevelElementAccessReadOnly 2
msdLevelElementAccessViewOnly 3
MsdLimits
msdLimitsMaxVertices 5000
msdLimitsMaxVi ews = 8
MsdMeasurementBase
msdMeasurementBaseDegree = 2
msdMeasurementBaseMeter = 1
msdMeasurementBaseNone = 0
MsdMeasurementSystem
msdMeasurementSystemEnglish = 1
msdMeasurementSystemMetric = 2
msdMeasurementSystemUndefined 0
MsdMessageCenterPriority
msdMessageCen t erPr i or i tyDebug = 13
msdMessageCenterPriorityError = 10
msdMessageCenterPrioritylnfo = 12
msdMessageCenterPr i orityNone = 14
ms dMessageCe nte r Pr i orit yWa rn i ng 11
MsdModelChangeType
md lM ode l ChangeActive = 5
mdlModelChangeBeforeAct i ve 11
mdlModelChangeBeforeCreate 15
md l Mode l ChangeBeforeDelete 6
md l Mode l ChangeBeforeName = 12
mdlModelChangeBeforeProperties = 14
mdlModelChangeBeforeSettings 13
mdlModelChangeBeforeUnCreate 9
mdlModelChangeBeforeUnDelete 16
mdlModelChangeCreate = 1
mdlModelChangeDelete = 2
mdlModelChangeName = 10
mdlModelChangePropagateAnnotationScale 17
mdlModelChangeProperties 3
mdlModelChangeSettings 4
md lM odelC hange Un Crea t e 7
mdlModelChangeU nDelete 8
MsdModelType
msdMode lTypeDefa ul t = -1
msdModelTypeExtraction 2
msd Mode lTypeNormal = 0
msdModelTypeSheet = 1
MsdN estOverrides
msdNestOverridesA l ways = 1
msdNestOverridesAsRequired 0
msdNestOverridesNever = 2
274 I Chapter 12: The MicroStation Object Model - Enums I
Msd RasterBlockType
msdRasterBlockTyp e lmage = 4
msdRast e rBl ockTypeLin e = 1
msdRasterBlockTypeStr i p = 3
msdRasterBlockTypeTile = 2
MsdRasterDisplayOrder(ommand
msdRasterDisplayOrderCommandBackward = 3
msdRasterDisplayOrderCommandForward = 2
msdRasterDisplayOrderCommandToBack = 1
msdRasterDisplayOrderCommandToFront = 0
MsdRasterDisplayPriorityPlane
msdRasterD isp layPriorityPlaneBack = 1
msdRasterDisp l ayPriorityPlaneFront = 3
msdRasterDisplayPriorityPlaneVector = 2
MsdRasterModificationType
msdRasterModificationType_ClipBoundary = 5
msdRasterModificationType_ClipMask = 4
msdRasterModificationType_Extendedlnformation = 0
msdRasterModificationType_GeoReferenceInformation = 1
msdRasterModificationType_Raster ln formation = 3
msdRasterModificationType_Re l oad = 6
msdRasterModificationType_Renderinglnformation 2
MsdReferenceSystem
msdReferenceSystemDgn 2
IThe En umeration List I 275
msdReferenceSys t emRaster 1
MsdRenderingMode
msdRenderingModeConstantShade = 5
msdRenderingModeCrossSection = 1
msdRe nder i ng Mode Hi dde nLine = 3
msdR enderingModePar t icle Trace = 11
msdRenderingModePhong = 7
ms dRender i ng ModeRadiosity = 10
msdRenderingModeRayTrace = 8
msdRenderingModeRe nderWireFrame 9
msdRenderingModeSmoothShade 6
msdRender i ngModeSo li dFil l = 4
msdRenderingModeWireFrame = 0
msdRenderingModeWireMesh = 2
MsdStandardsCheckerReplaceChoice
msdStandard s CheckerReplaceCh oiceAbo rt = 4
msd Stan dard s Ch eckerReplaceChoiceFi x = 1
msdStandardsCheckerRepla ceChoiceMarkIgn ored = 2
msdStandardsCheckerReplaceChoiceMarkNotIgnored 3
msdStandardsCheckerRep l ac eChoiceSkip = 0
MsdStandardsCheckerReplaceOptions
msdStandardsCheckerReplaceOptionCanFix = 2
msdStandardsCheckerReplaceOptionCanIgnore 1
MsdStatusBarArea
msdStatusBarAreaLeft 16
msdStatusBarAreaMiddle = 15
MsdTagType
msdTagTypeBinary = 5
msdTagTypeCharacter = 1
msdTagTypeDouble = 4
msdTagTypeLonglnteger 3
msdTagTypeShortlnteger = 2
276 I Chapter 12: The MicroStation Object Model - Enums I
MsdTangentElementOutputType
msdTangen t Arcs = 1
msdTangentCircles = 0
msdTange ntTr i angles 2
MsdTangentlnterpolationType
msdTangentFromCircleFit = 1
msdTangent Fr om Cu bi c Fit = 2
msd TangentFromCurve = 0
MsdTextDirection
msdTextDirect ionHori zontal = 0
msdTextDirectionRightToLeft = 8
msdTextDirectionVertical = 4
msdTextDirectionVerticalMultiLineRightToLeft 2
MsdTextJustification
msdTextJustificationCenterBottom 8
msdTextJustificationCenterCenter 7
msdTextJustificationCenterTop = 6
msdTextJustificationLeftBottom = 2
msdTextJustificationLeftCenter = 1
msdTextJustificationLeftTop = 0
msdTextJustificationRightBottom = 14
msdTextJustificationRightCenter = 13
msdTextJustificationRightTop = 12
MsdTextNodelineSpacingType
msdTextNodeLineSpacingTypeAtLeast 3
msdTextNodeLineSpacingTypeAutomatic 1
msdTextNodeLineSpacingTypeExact = 0
msdTextNodeLineSpacingTy peExactFr omLineTop 2
MsdV7 Action
msdV7ActionAskUser = 0
msdV7ActionUpgradeToV8 1
msdV7ActionWorkmode = 3
I Review I 277
MsdViews
msd Vi ew1 1
msdView2 2
msdView3 4
msdView4 8
msdView5 16
msdView6 32
msdView7 64
msdView8 128
ms dView All = 25 5
msdV i ew None = 0
MsdXDatumType
msd XDatumTypeBinaryData = 1004
msdXDatumTypeControlString = 100 2
msdX Datu mTypeData ba se Ha nd l e = 1005
msdX DatumTypeD i stance = 1041
msdXDatumTypelnt16 1070
msdXDatumTypelnt32 10 71
msdXDatumTypeLevel 1003
msdXDatumTypePoint 1010
msdXDatumTypeReal = 1040
msdXDatumTypeScaleFactor 1042
msdX DatumTypeString = 1000
msdXDatum TypeUns upported = 0
msdX Datum TypeWor ldD irect i on = 1013
ms dXD atumT ypeW orldS pace Di s plac ement = 1012
msdXD atumTypeWorld SpacePos i t i on = 1011
REVIEW
As we continue through this book, we will see examples of using
enumerations in the code samples.
As we pointed out in the objects chapter, the Object Browser is useful in
finding and determining how to use enumerations.
278 I Chapter 12: The MicroStation Object Model - Enums I
13 The MicroStation Object
Model - Types
Type Po in t3d
X As Double
Y As Double
Z As Double
End Type
The Point3d type has three members: X (which is a Double), Y (which is
a Double) and Z (which is a Double).
Sub TestPoint3d ()
Di m StartPo i nt As Po i nt 3d
Dim EndPoint As Po i nt3d
Dim My Line As LineElement
StartPoint . X 1. 5
StartPoint . Y = 2. 5
279
280 I Chapter 13: The MicroStation Object Model- Types I
Star t Poi nt.Z = 3 . 5
End Po int. X 4
EndPoint.Y = 0
EndPoint.Z = 0
Set MyLine = CreateLineElement2(Nothing. StartPo i nt. EndPoint)
ActiveModelReference.AddElement MyLine
End Sub
We declare two variables with a type of "Point3d". We assign coordinate
values to the X, Y, and Z elements of these variables. They are then used
with the CreateLineElement2 method. Here is the declaration for
"CreateLineElement2" :
Type MsdACSType
Just if icat ion As MsdDataEntryRegionJustificat i on
Length As Long
StartPosition As Long
End Type
Type MsdAngleAccuracy
RowX As Point3d
RowY As Po~ nt3d
RowZ As Poi nt3e
End Type
Type MsdAngleAccuracy
Base As MsdMeasurementBase
Label As Stri ng
System As MsdMeasurementSystem
UnitsPerBaseDenominator As Double
UnitsPerBaseNumerator As Doub l e
End Type
Type MsdAngleFormat
Details As String
Msg As Str i ng
Priority As MsdMessageCenterPriority
End Type
Type MsdAngleMode
Norma 1 As Poi nt3d
Origin As Point3d
End Type
Type MsdAttachMode
X As Double
Y As Double
End Type
Type MsdBsplineCurveOffsetCuspType
X As Double
Y As Double
Z As Double
End Type
Type MsdBsplineCurveOffsetCuspType
High As Point3d
Low As Poi nt3d
End Type
282 I Chapter 13: The Mi croStatio n Object Mode l - Types I
Type MsdBsplineCurveType
Duu As Point3d
Duv As Point3d
Dvu As Po i nt3d
Dvv As Poi nt3d
End Type
Type MsdBsplineSurfaceType
X As Doub l e
Y As Dou bl e
Z As Doub l e
End Type
Type MsdBsplineSurfaceType
Type As MsdXDatumType
Va l ue As Varian t
End Type
Each of these types is available to us when we are using MicroStation
VBA. The "Type", "End Type" declaration as shown is a standard VBA
convention. As a matter of fact, we can create our own "Types" inside
VBA. Custom Types are declared in the General Declarations area of a
I Review I 283
Type Po'nt4d
X As Double
Y As Double
Z As Double
A As Double
End Type
If this declaration is made, we can declare variables as follows:
REVI EW
Types are similar to objects. An object has properties. A type has
members which are similar to properties. One of the most common
types we use in MicroStation is the Point3d type. It has members of X, Y,
and Z. Each of these members are declared as Doubles.
284 I Chapter 13: The MicroStation Object Model- Types I
14 The MicroStation Object
Model - Events
End S ub
E n d Sttb
285
286 I Chapter 14: The MicroStation Object Model - Events I
events are triggered as a worksheet's cell value changes and when the
user moves from one cell to another.
There are two ways we can capture and make use of MicroStation
events. One is to declare a variable in a class module or a form as an
application and using the "WithEvents" keyword. This exposes two
events: OnDesignFileOpened and OnDesignFileClosed. The majority of
MicroStation events are accessed through the use of interfaces.
MicroStation has exposed much more than simple events through the
use of interfaces, which are discussed in detail in Chapters 22
through 26.
File Opened
....C:.)M!q.9.~~<!~!Q[\.Y.~A?)f!!~.!.'.9.gD. .........................
C:\Microstation VBA2\Mathcad Model.dgn
File Closed
C:\Documents and Settings\AII Users\Application Data\Bentley\WorkSpace\Projects\Examples\E
C:\Microstation VBA2\file l .dgn
I OnDesignFileOpened and OnDesignFileClosed I 287
Each time the OnDe sig nF ile Ope ned event is triggered, we add the
DesignFileName parameter to the IstOpened ListBox. When a file is
closed, it is added to the IstClosed ListBox.
We want to display this fo rm as modeless, so we will display it by
running the next macro:
Sub ShowEvents ( )
frmEvents . Show vbModeless
End Sub
REVIEW
Events are triggered as users interact with software. MicroStation events
are primarily exposed through the use of interfaces (covered later). The
OnDesignFileOpened and OnDesignFileClosed events can be exposed
by declaring the MicroStation.Application object "WithEvents" in a
Class Module or UserForm. More information on the use of
"WithEvents" can be found in the standard VBA help file.
15 Adding To Documents
In this chapter:
~ Graphical Elements
~ Creating New Documents
~ Security Issues with Creating Data
GRAPHICAL ELEMENTS
There are two steps to adding elements to our design files. First we
create the element in memory. Then we add the element to our design
file. As you will see, there is often more than one way to create the
element. We will demonstrate multiple examples of each creation
method.
Lines
"The shortest distance between two points is a straight line:' If this is
true, we should be able to create a line by providing two points, right?
289
290 I Chapter 15: Adding To Documents I
Well, that is one way to create a line. We can also provide an array of
vertices if we want to draw more than one line.
~ Function CreateLineE l ementl(Template As Element,
Vertices() As Point3d) As LineElement
~ Function CreateLineElement2(Template As El ement,
StartPoint As Point3d, EndPoint As Point3d) As
LineElement
Sub TestCreateLineA ()
Dim StPt As Point3d
Dim EnPt As Po i nt3d
Dim myLine As LineElement
EnPt.X = 4: EnPt.Y = 6: EnPt.Z = 8
Set myLine = CreateLineE l ement2(Nothing, StPt , EnPt)
ActiveModelReference . AddE l ement myLine
End Sub
TestCreateLineA uses the Create LineElement2 method to create a new
line element. It does so using a start point and an end point.
Sub TestCreateLineB()
Dim StPt As Point3d
Dim EnPt As Point3d
Dim myLine As LineElement
'Line 1
Stpt.X = 0: StPt.Y = 0: Stpt.Z = 0
En Pt.X = 4: EnPt.Y = 0: EnPt.Z = 0
Set myLine = CreateLineElement2(Nothing, StPt, EnPt)
ActiveModelReference.AddElement myLine
'Line 2
StPt.X = 4 : StPt.Y = 0 : Stpt.Z = 0
EnPt.X = 4: EnPt.Y = 4 : EnPt.Z = 0
Set myLine = CreateLineElement2(Nothing, StPt , EnPt)
ActiveModelReference . AddElement myLine
' Line 3
Stpt.X = 4: StPt . Y = 4 : StPt.Z = 0
EnPt.X = 0: EnPt . Y = 4 : EnPt.Z = 0
Set myLine = CreateLine[lement2(Nothing, StPt, [nPt)
ActiveModelReference.AddElement myLine
' Line 4
Stpt .X 0: Stpt.Y 4: Stpt.Z 0
EnPt.X = 0: EnPt.Y 0: EnPt . Z 0
I Graphical Elements I 291
Sub TestCreateLineC ()
Dim LinePoints(O To 4 ) As Poi nt3d
Dim myLine As LineElement
LinePoints(O).X 0: LinePoints(O).Y 0
LinePoints(l) . X 4 : LinePoin ts(l).Y 0
LinePoints(2).X 4: LinePo i nts(2) . Y 4
LinePoints(3) . X 0: LinePo i nts(3) . Y 4
Li ne Poi nts(4).X 0: LinePo i nts(4).Y 0
Set my Line = CreateLineElement1(Nothing , LinePoints)
Act i veModelReference.AddElement myLine
End Sub
As we can see in Test CreateL i neC, we can supply an array of Point3d
types and use a single Cr eateL i neEl ementl Method to create four lines.
NOTE: When we declare a numeric variable, a value of zero (0) is
automatically assigned to the variable. Knowing this, we can leave
the .Z element of each point alone and it will be assigned a value of
zero by default. We could have left out th e .X and . Y elements that
were to be assigned values of zero as well, but keeping them in makes
the code much easier to read. Also, note that we are putting two lines
of code on the same line. We can do this by using the colon (:) symbol.
This keeps our vertices on the same line of code and can make it easier
to read the code.
In our next example, we are going to create a procedure that allows us to
specify x, y, z elements for the creation of 3d Lines. We want to be able to
provide any number of x, y, z sets of elements so we will use the
ParamArray keyword in our parameter declaration.
Sub TestCreate3dLines ( )
Create3d Lines 0, 0, 0, 4 , 0 , 0 , 4 , 4, 0 , 0 , 4, 0 , 0, 0,
Create3dLines 0, 0, 0, 4, 4 , °
Create3d Li nes 0, 4, 0, 4, 0, °
Create3dLines 0, 4, 0, 4, °
Create3dLines 0, 4, °
End Sub °
Our test procedure, TestCreate3d Li nes , calls our newly created
procedure Crea te3 dLin es five times. In the first instance, a square is
created from (0,0,0) to (4,0,0) to (4,4,0) to (0,4,0) and back to (0,0,0).
The next one draws a line from (0,0,0) to (4,4,0). Next we draw a line
from (0,4,0) to (4,0,0). The next two lines are put in to test our
ParamArray validation code. We are unable to draw a line from (0,4,0)
to (4,0) because the second point is only given two elements (x and y)
and we are requiring three elements per point. The last one attempts to
draw a line from (0,4,0) to ... to nothing. We cannot draw a line with
only one point. Here are the two message boxes in the order in which
they appear.
Once a line is created, we can make changes to its properties such as its
color, level, or linestyle properties.
294 I Chapter 15: Adding To Documents I
In MicroStation's Color
Table dialog box, if we
Let's draw a couple of lines and change their color to red (255, 0, 0).
Sub TestCreateLineD ()
Dim LinePo i nts(O To 1) As Point3d
Di m myL i ne As LineElement
Li nePoints(O) . X = 0: Li nePo ints(O ).Y = 0
LinePoints(l).X = 4: LinePoints(l).Y = 4
Set myLine = Create Li neElement1(Nothing, LinePoints)
myLine.Color = 3
ActiveModelReference . AddElement myL i ne
LinePoints(O).X = 0: LinePoints(O).Y = 4
LinePoints(l).X = 4 : LinePoints(l).Y = 0
Set myL ine = CreateLineElement1 ( Nothing, LinePoints )
myL i ne . Color = 3
ActiveModelReference.AddElement myLine
End Sub
Two lines are created with their color properties changed to color
number 3 (red).
Here is another way we could accomplish the same task:
Sub TestCreateLineE ()
Dim LinePoints(O To 1) As Point3d
Dim myLine As LineElemcnt
Dim myLine2 As LineElement
LinePoints(O) . X = 0 : LinePoints(O).Y = 0
LinePoints(l ) . X = 4 : LinePoints(l).Y = 4
Set myLine = CreateLineElement1(Nothing, LinePoints)
I Graphical Elements I 295
myLine . Color = 3
Act iveM odelReference.Add Element myLine
LinePoints (O).X = 0 : LinePoints(O).Y = 4
LirePoi~ts(l).X = 4: LinePoints(l).Y = 0
Creating Shapes
A shape is a series of lines that are joined together into one element.
Here is the declaration for CreateShapeElementl:
~ Functi on Cre at eShape El ementl( Template As El ement .
Vert i ces( ) As Poi nt 3d . [ Fil l Mode As MsdFi ll Mode
msd Fil lM odeUseAct iv e J ) As Shap e El ement
Here is a procedure that creates a triangle.
Sub TestCreateShapeA ()
Di m myShape As ShapeElement
Dim Shape Po ints(O To 2) As Point3d
ShapePoints(O) . X 0 : ShapePoints(O) . Y 0
ShapePoints(l).X = 2: ShapePoints(l) . Y 0
ShapePoints(2).X = 1: ShapePoints(2).Y 1
Set myShape = CreateShapeElement1 ( Nothing. ShapePoints )
ActiveModelReference . AddElement myShape
End Sub
When this code is run, a triangle is created and added to the
ActiveModelReference. Notice that we do not need to close the triangle
by providing a fourth point at (0, 0, 0). Shapes are always closed.
296 I Chapter 15: Adding To Documents I
A comparison of the declaration and the use of CreateShapeEl ementl
reveals that we did not use the optional FillMode parameter. By default,
the FillMode parameter uses the active setting in MicroStation. Let's
copy and paste TestCreateShapeA, rename the new procedure to
TestCreateShapeB and supply a FillMode parameter:
Sub TestCreateShapeB( )
Dim myShape As ShapeElement
Dim ShapePoints(O To 2) As Point3d
ShapePoints(O) . X 0: ShapePoints(O).Y 0
ShapePoints(l).X = 2: ShapePoints(l) . Y 0
ShapePoints(2).X = 1: ShapePoints(2).Y 1
Set myShape = CreateShapeElement1( Nothing. ShapePoints . _
msdF i 11 ModeFi 11 ed)
ActiveModelReference.AddElement myShape
End Sub
TestCreateShapeB creates a filled triangle. If the resulting triangle does
not look like it is filled, the fill setting in view attributes may not be
selected (Settings> View Attributes).
Let's build on our knowledge of creating shapes. Now we are going to
create a function that creates a regular polygon based on a center point,
a number of sides, and a radius. The polygon we create will be inscribed
within the radius we provide.
Sub TestCreatePolygon ()
Di m CPoint As Poi nt3d
Dim myShape As ShapeE'ement
Set myShape = CreatePolygon(CPoint. 6 . 1)
Act'veModelReference.AddElement myShape
End Sub
Our TestCre at ePolyg on procedure declares a variable as a Point3d. No
modification is made to the X, Y, or Z elements of the point so the
polygon is created centered around (0, 0, 0).
Creating Circles
A circle is defined by a center point and a radius or diameter. We create
circles in MicroStation VBA by using the CreateEll i pseEl ementl and
CreateEll i pseEl ement2 methods.
~ Function CreateE l l ipseElementl(Template As Element.
PerimeterPointl As Point3d. PerimeterPo i nt2 As
Point3d. PerimeterPoint3 As Point3d . [Fi l lMode As
MsdFillMode = msdFi l lModeUseActiveJ) As
Ell i pseEl ement
~ Function CreateEllipseElement2(Temp l ate As Element.
Origin As Point3d. PrimaryRadius As Do uble.
SecondaryRadius As Double. Rotation As Matrix3d.
[Fil l Mode As MsdFi l lMode = msdFillModeUseActiveJ) As
Ell i pseEl ement
298 I Chapter 15: Adding To Documents I
We will begin with CreateEll i pseEl ement 2.
Sub TestCreateCircleA()
Dim CPoint As Point3d
Di m myEll ipse As Ell i pseEl ement
Dim rotMatrix As Matrix3d
CPoint . X = 2. 5: CPoint.Y = 2 . 5
Set myEllipse = (reateEllipseElement2(Nothing, (Point, 0.5 , 0.5, _
rotMatrix)
ActiveMode1Reference.AddE l ement myEl1ipse
End Sub
The center point is set at (2.5, 2.5, 0) and we are using a radius of 0.5. We
supply the same value for the PrimaryRadius parameter as we do for the
SecondaryRadius parameter. This results in a circle. If the primary and
secondary radii values are different, an ellipse is created.
Sub TestCreateCircleB ()
Dim CPoint As Poi nt3d
Dim my E11 ips e As El l ip seE1ement
Dim rotMatrix As Matr i x3d
Dim CirRad As Double
CPoint.X = 2. 5: CPoint . Y = 2.5
For Ci rRad = 0 . 5 To 2 Step 0 .12 5
Set myE1lip se = CreateEl1ipseElement2(Nothing, CPoint, _
CirRad , CirRad , rotMatrix)
ActiveModelReference.AddElement myE1l ipse
Next CirRad
End Sub
Test Crea t eCir e1eBcreates a series of corradial circles with radii ranging
from 0.5 to 2 in .125 unit increments.
The next procedure allows the user to select the center point of the circle
to be drawn. The radius used is 0.5.
Sub TestCreateCircleC ()
Di m CPoint As Point3d
Dim myE 1lipse As EllipseE1ement
Dim rotMatr i x As Matrix3d
Dim inputOueue As CadlnputQueue
Dim inputMessage As CadlnputMessage
Set inputOueue = CadlnputOueue
I Graphica l Elements I 299
Set i nputMessage = _
inputOueue . GetInput(msdCadInput TypeDa taPoint , _
msdCadInputTypeAny)
Do
Select Case inputMessage.InputType
Case msdCadInPJtTypeDataPo'nt
CPoint = inputMessage . point
Set myEllipse = CreateEllipseElement2(Nothing,_
CPoint, 0.5, 0.5, rotMatrix)
ActiveModelReference.AddElement myEllipse
Exit Do
Case msdCadInputTypeReset
Exit Do
End Select
Loop
End Sub
The last circle-creating procedure we will write allows the user to select
two points. A circle is then drawn through the selected points.
Sub TestCreateCirc l eD ()
Dim CPoint As Point3d
Di m StPoint As Po i nt3d
Dim EnPoint As Point3d
Dim myEll i pse As Ell i pseElem ent
Di m rotMatr i x As Mat r ix3d
Di m i nputOueue As Cad I nput Oueu e
Dim i nputMessa ge As CadInputMessage
Dim CirRad As Double
Set inputOueue = CadInputOueue
Set inputMessage = _
inputOueue.GetInput(msdCadInputTypeDataPoint, _
msdCadlnputTypeAny)
Do
Select Case inputMessage.InputType
Case msdCadInputTypeDataPoint
StPoint = inputMessage . point
Exit Do
Case msdCadlnputTypeReset
Exit Sub
End Select
Loop
300 I Chapter 15: Adding To Documents I
Set i nputMessage i nputO ueue . Getlnput _
(msdCad l npu t Ty peDat aPo i nt , _
msdCad l nput TypeAny)
Do
Select Case inputMessage.lnputType
Case msdCadlnput TypeDataPoint
EnP oi nt = i nputMessage .poi nt
Exi t Do
Case msdCadlnputType Reset
Ex it Sub
End Se l ect
Loop
CPoi nt . X Stpo i nt . X + (EnPo i nt . X St Po i nt . X) / 2
CPo i nt.Y StPoint.Y + (EnPo i nt.Y StPoint . Y) / 2
CPoint . Z StPoint . Z + ( EnPoint.Z StPo i nt . Z) / 2
CirRad = Po i nt3dDistance(StPoint, EnPoint) / 2
Set myEll i pse = CreateE llip se Elemen t 2(Not hi ng, CPoint, _
Ci r Rad, Ci rRad , rotMatrix)
Act i veModelReference.AddE l ement myEllipse
End Sub
We calculate the center point of the circle by using the selected points.
We also use the MicroStation VBA Po i nt3dO i stance function to give us
the distance between the selected points.
Creating Ellipses
We have already used code that could create ellipses but the code created
circles because the primary and secondary radii were the same. Let's
look at three examples of creating ellipses.
Sub TestCreateEllipseC ()
Dim CPoint As Point3d
Dim myEllipse As EllipseElement
Dim rotMatrix As Matrix3d
CPoint.X = 2 . 5: CPoint . Y = 2 . 5
rottvlatr i x.RowX . X = 2
rottvlat ri x . RowY . X = 4 : rotMatr i x . RowY . Y = 5
Set myEllipse = CreateEllipseElement2(Nothing . CPoint. 1 . 0 . 5. _
rotMatrix)
ActiveMode l Reference.Add Element myE l lipse
End Sub
After running the above procedures, what do we find? Two of the three
procedures shown above create ellipses. However, the procedure
TestCreateE l l i pse8 created a circle. The method Create Ell i pseEl ementl
always creates a circle through the three points provided.
Creating Arcs
We have five different ways we can create arcs in MicroStation VBA.
1 Function CreateArcElementl (Template As Element, StartPoint As
Point3d, CenterPoint As Point3d, EndPoint As Point3d) As
ArcElement
2 Function CreateArcElement2(Template As Element, CenterPoint As
Point3d, PrimaryRadius As Double, SecondaryRadius As Double,
Rotation As Matrix3d, StartAngle As Double, SweepAngle As
Double) As ArcElement
3 Function CreateArcElement3(Template As Element, StartPoint As
Point3d, PointOnCurve As Point3d, EndPoint As Point3d) As
ArcElement
302 I Chapter 15: Add ing To Documents I
4 Function CreateArcElement4(Template As Element, StartTangent
As Ray3d, EndPoint As Point3d) As ArcElement
5 Function CreateArcElementS(Template As Element, Chord As
Segment3d, ArcLength As Double, Plane Point As Point3d) As
ArcElement
Let's look at a few ways to use these methods.
Sub TestCreateArcA ()
Dim CPoint As Point3d
Dim StPo i nt As Point3d
Dim EnPoint As Point3d
Dim myArc As ArcElement
CPoint . X = 1: CPoint . Y = 1
StPoint . X = 4: StPoint . Y 1
EnPo i nt . X = 1: EnPo i nt . Y 4
Set myArc = (reateArcElementl(Nothing . StPoint . (Point . EnPoint)
ActiveModelReference.AddElement myArc
End Sub
Sub TestCreateArcB ()
Di m CPoint As Poi nt3d
Dim rotMatrix As Matrix3d
Dim myArc As ArcE l ement
CPoint . X = 1: CPo i nt.Y = 1
Set my Arc = CreateArcElement2(Nothing. CPoint, 0.5, 0.5, _
rotMatri x, 0, Pi)
ActiveModelReference . AddElement myArc
End Sub
Sub TestCreateArcC ()
Dim PointA As Point3d
Dim Po int B As Point3d
Dim PointC As Po i nt3d
Dim myArc As ArcElement
PointA . X 1: PointA.Y
PointB . X = 2: PointB.Y = 2
PointC . X = 1: Po i ntC.Y = 3
Set myArc = CreateArcElement3(Nothing , PointA , PointS, PointC)
ActiveModelReference.AddElement myArc
End Sub
I Graphical Elements I 303
Sub Te s tCreateArcE ()
Di m myArc As Arc Element
Di m mySeg As Segment3d
Di m myPoi nt As Point3d
mySeg . startPo i nt.X = 1 : mySeg . startPoint.Y = 1
mySeg . End Point . X = 4 : mySeg . EndPoint.Y = 4
myPoint.X = 3.5 : myPoint . Y = 3 : myPoint . Z = 0
Set myArc = CreateArc Element5 ( Nothing , mySeg , 8 . 5 , myPoint)
Ac t iveModelRe f erence . AddEle ment myArc
End Sub
Creating Text
Text is easy to create by using the CreateTextElementl method.
~ Function CreateTextElementl(Te mp late As Element,
Tex t As String, Origin As Point3d, Rotation As
Matrix3d) As Text Element
Here is an example of creating nine text elements spaced 0.5 units away
from each other.
Sub TestCreateTextA ()
Dim myText As TextElement
Dim TextPt As Point3d
Dim rotMatrix As Matrix3d
Dim I As Double
For I = 1 To 9
TextPt.Y = TextPt.Y - 0.5
304 I Chapter 15: Adding To Documents I
Se t myText= CreateTextEleme ntl(N ot hing, "N ote " & I &
":", TextPt, rotM atrix)
Active~cdelReference.AddEle~ent myText
Next
End Sub
~Note 1.:
iN. ote
, " .
.
!
.2:
. I
iNote 3: ,
,
··········· 4·· ·:···· I
. . .. ..... t
N. ote ·,:
INoteS: ! I
"N-'-----·---·---·----··'-6'--· -- - ------+--
. ----·ote .i
! . . i .. • • •• I
i ; I!
'Note 7:::
-"'-.-:-------------8'~
'l'Iote ·· .
Creating Cells
Thus far, all elements we have created have been added to the design file
as individual elements. When we begin working with cells, we work with
multiple elements as a single cell. We create the elements in the same
manner as when we are adding them to our model but instead of adding
I Graphical Elements I 305
the created element to the model we add it to the cell. We have three
options for creating cells.
1 Function CreateCellElementl (Name As String, ElementsO As
_Element, Origin As Point3d, [IsPointCell As Boolean]) As
CellElement
2 Function CreateCellElement2(CellName As String, Origin As
Point3d, Scale As Point3d, TrueScale As Boolean, Rotation As
Matrix3d) As CellElement
3 Function CreateCellElement3(CellName As String, Origin As
Point3d, TrueScale As Boolean) As CellElement
Our first example creates a cell named "Box". Four lines are added to an
array of elements. This array is used when we create the cell.
Sub TestCreateCellA ()
Dim myCell As CellElement
Dim BoxL i nes(O To 3) As Element
Dim OriginPoint As Poi nt3d
Se t BoxL i nes(O) = Create Lin eEle me nt2(Nothing, -
Point3dFromXYZ(0 , 0, 0) , Point3dFromXYZ(4, 0 , 0))
Set BoxLines(l) = CreateL i neElement2(Nothing, _
Point3dFromXYZ(4, 0 , 0) , Point3dFromXYZ (4, 4, 0) )
Set BoxLines(2) = CreateLineElement2(Nothing, _
Point3dFromXYZ(4, 4, 0) , Point3dFromXYZ(0 , 4, 0) )
Set BoxLines(3 ) = CreateLineElement2(Nothing , -
Point3dFromXYZ(0, 4, 0) , Point3dFromXYZ(0, 0, 0) )
OriginPoint.X = 2: OriginPoint.Y = 2
Set myCell = CreateCellElementl( "Box", BoxLines, OriginPoint)
ActiveModelReference.AddEl ement myCell
myCell . Redra~1
End Sub
Tes tC rea teCe 11 A creates A 4-unit square with an origin of (2,2, 0).
Sub TestCreateCellB ()
Dim myCell As CellElement
Dim CellElements(O To 6) As Element
Dim OriginPoint As Point3d
Dim rotMatrix As Matrix3d
Set CellElements(O) = CreateLineElement2(Nothing,
306 I Chapter 15: Addin g To Docum ents I
Point3dFromXYZ(O , 0 , 0) , Po i nt3dFromXYZ(4 , 0 , 0))
Set CeIIElements(l) = CreateLineElementZ(Nothing , _
Po i nt3dFromXYZ(4 , 0 , 0) , Point3dFromXYZ(d , 4 , 0) )
Note that we specify the file name of the cell library we want to attach
the cell to. We do not specify the full path, only the file name.
Ble
o !Jse Shared Cells o Q.isplay All Cells In Path
Name Description , Type Annotation , Where
:. :.
Active Cells
EJacement I 80x3 Point I Element
Terminator I NONE Pgttern I NONE
Here are two methods that create new design files. Crea t eOesignF il e
allows us to specify whether the new file is to be a 2D or 3D file by
specifying the seed document. Let's look at a couple of examples.
Sub TestCreateDesignFileA ()
Dim myFile As DesignFile
Application . ActiveDesignFile.Close
Set myFile = CreateDesignFile( "seed2d " ,
"C:\MicroStation VBA\filea.dgn", True)
End Sub
TestC reateOes i gn Fil eA creates a new 2D design file. The file path and
name are specified. After the Crea teOes i gnF i 1e line of code is executed,
the new file is created and opened. It becomes the active document. If
the file already exists, a new file is created and overwrites the existing
file. Since we don't receive any warning of this, we should check if the
file already exists.
Sub TestCreateDesignFileB ()
Di m my Fi le As Des i gnF i le
Di m myF i l eNa me As Str i ng
my Fi leN ame = "C: \M i cr oStation VBA\filea . dgn "
If Dir (my Fil e Name) = "" Then
Set myFi l e = Cr eate Design Fi l e( "seed3d ", my Fil eName , Tr ue)
Els e
Ms 9 Box "The f i 1e " & my Fi 1eName & " a 1 rea dye xis t s . ", _
vb Crit i ca 1
En d If
End Sub
If the file we want to create exists (we know this by using the Dir
function), we inform the user it already exists. If it does not exist, we
create a new 3D file.
Let's look at one more example:
Sub TestCreateDesignFileC ()
Dim myFile As DesignFile
Dim I As Long
For I = 1 To 10
Set myFile = CreateDesignFile( "seed2d ", _ "C:\MicroStat i on
VBA \ f i 1 e" & I & ". d 9 n" , Fa 1 s e )
Next
End Sub
I Security Issues with Creating Data I 309
file is a new 2D file and th e til f ile4 ,dgn 34 KB Bentley ~li croStation Design File
l:il fileS,dgn 34 KB Bentley ~1icroStation Design File
files are not opened in MicroS - ~file6,dgn 34 KB Bentley ~licroStation Design File
~file7,dgn 34 KB Bentley i'licroStation Design File
tation (the False Parameter) . l:il file8, dgn 34 KB Bent ley ~licroS tation Design File
liJ file9,dgn 34 KB Bentley ~1i c r oStation Design File
b:jJ file lO,dgn 34 KB Bentley i'licroStati on Design File v
-
<' '-',,_-'.L" '"·'"'"'=c.:;C"~C'·.C-'==. >
REVIEW
Simple geometry can be created with the knowledge of only a few
MicroStation VBA calls. The Object Browser and MicroStation VBA
help file can be used to find other data creation alternatives and can
provide examples of how to use them.
310 I Chapter 15: Adding To Documents I
16 Searching In Files
Our design files range in complexity from one or two elements to many
thousands. The number of elements can vary as well as the element
types (lines, circles, arcs, text) and colors. Levels, line styles and classes
can differ from element to element. Line weights and transparency can
also vary. As we begin searching in our files, we will learn how to
discover these properties we find in our files.
In this chapter:
[B The Basics of Searching Files
[B Using ScanCriteria
[B Multiple Combinations of Criteria
[B Reviewing Three Collection Methods
[B Scan Criteria Methods
Sub TestScanAllA ()
Dim myElement As Element
Dim myEnum As ElementEnumerator
311
312 I Chapter 16: Sea rchi ng In Fil es I
Set myEnum = ActiveModelReference . Scan()
While myEnum.MoveNext
Set myElement = myEnum.Current
Debug.Print myElement.Type
Wend
End Sub
This procedure prints the type
property value of each element in the
active model to the Immediate
97 Window.
66
96 Running the procedure TestScanA 11 A
96
96
results in a list of numbers telling us
96 the type of element found. This
66
66 number references the
6 msdElementType enumeration.
4 ."' .!
msdElementTypeDimension = 33
msdE l ementTypeEllipse = 15
msdE l ementTypeGroupData = 5
msdElementTypeLevelMask = 99
msdElementTypeLevelSymbology 10
msdElementTypeLine = 3
msd ElementTypeL i neStr i ng = 4
msdElementTypeMatr i xDoubleData = 103
msdElementTypeMatrixHeader = 101
msdElementTypeMatrixlntegerDa t a = 102
msdElementTypeMeshHeader = 105
ms dElementTypeMicroS t atio n = 66
msdElemen t TypeMultiLin e = 36
msdElementTypeNamedGroupComponent = 111
msdElementTypeNamedGroupHeader = 110
msdElement TypePointString = 22
msdElementTypeRa sterCompo nent = 88
msdE l ementTypeRa st erFrame = 94
msdElementTypeRasterHeader = 87
msdElementTypeRasterReference = 90
msdElementTypeRasterReferenceComponent 91
msdElementTypeReferenceAttachment = 100
msdElement Ty peReferenceOverride = 108
msdElementTypeShape = 6
msdElementTypeSharedCel l = 35
msdElementTypeSharedCellDefinit io n 34
msdElementTypeSolid = 19
msdElementTypeSu r face = 18
msdEleme ntTypeTab l e = 96
msdElementTypeTableEntry 95
msdElementTy peT ag = 37
msdElementTypeText = 17
msdElementTypeTe xtNode = 7
msdEleme ntTyp eView = 98
msdElementTypeViewGroup = 97
A review of the Immediate window, shown previously, shows the first
three unique element types are 9, 96, and 97. Referring to the list above
tells us the first three element types found were:
314 I Chapter 16: Searching In Files I
msdE1ementTy peDesignF i1 eHeader 9
msdE 1eme ntTypeTab1e = 96
msdE1ementTypeV i ewGroup = 97
Not exactly lines, circles, or arcs, right? MicroStation design files are
composed of far more than what we see on the screen as we are working
with MicroStation. What are the next three element types? 66, 6, and 4.
msdE1ementTypeMicroStation = 66
msdE1ementTypeShape = 6
ms dE1ementTypeLineString = 4
Now we're getting somewhere. We can see shapes and linestrings.
We are going to do a lot of copy and paste operations in this chapter.
Let's begin by copying and pasting TestScanA 11 A as TestScannA 11 B.
Sub TestScanAllB ()
Dim my Ele ment As El ement
Dim myEnum As Elemen tEnu me rat or
Set myEnum = ActiveModelReference . Sca n()
Whi l e my Enu m.M ove Next
Set myElement = myE num . Current
Select Case myElement.Type
Case msdElement TypeArc
Dim myArc As ArcElement
Set myArc = my Element
Case msdElementTypeCurve
Dim myC urve As CurveElement
Set myCurve = myElement
Case ms dEl eme nt Ty pe Lin e
Dim myL i ne As Li ne El ement
Set myL i ne = myE l ement
Case msd Elem ent Type Text
Dim myText As Text Element
Set my Text = my Element
Case Else
Debug . Pr i nt myElement . Type
End Se l ect
Wend
End Sub
We can make the use of a Se1ect ... Cas e statement to allow us to
perform actions based on the Element.Type property. As we cycle
IThe Basics of Searching Files I 315
Sub TestScanAl lC ( )
Dim myElement As Element
Dim myE nu m As ElementEnumerator
Set myEnum = ActiveModelReference.Scan()
Whi l e myEnum . MoveNext
Set myElement = myEnum.Current
Select Case myElement . Type
Case msdElementType Text
Di m myText As TextElement
Set myText = myElement
myText .T ext = UCase(myText . Text)
End Select
Wend
End Sub
Now, our procedure is only going to react to text elements. And what are
we doing to the text element? UCa s e capitalizes everything. The result of
this procedure should be the capitalization of all text elements, right?
316 I Chapter 16: Searching In Files I
After this code is executed we should find that nothing has changed.
How is this possible? The code is capitalizing the text. Let's take a look at
the next procedure and see if we can find what is missing.
Sub TestScanAllO ()
Dim myElement As Ele ment
Dim myEnum As ElementEnumerator
Set myEnum = ActiveModelReference.Scan()
While myEnum.MoveNext
Set my El ement = my Enu m. Cur ren t
Select Case myEleme nt . Type
Case msdE l eme nt Type Tex t
Di m myText As TextElement
Set myText = myE l ement
myText . Text = UCase(myText.Text)
myText.Rewrite
End Select
Wend
End Sub
If we don't rewrite the element to the model, the text element may be
modified in memory but the change is not actually made to the design
file.
USING SCANCRITERIA
Now, let's suppose we are working with a large file. It is composed of
thousands of elements but only four of them are TextElements. If we run
the code shown above, the TextElements will be capitalized to be sure.
However, it may take a while because each and every element in the
design file is reviewed. Let's make our code more efficient by working
only with text elements. We accomplish this through the use of an
ElementScanCriteria object.
Sub TestScanFilterA ()
Dim my Enum As El emen t Enume r ator
Dim my Fi lter As New ElementScanCriteria
Dim ElementCounte r As Long
myFilter . lncludeType msdE l ement TypeText
myFi l ter . lnclude Type msd ElementTypeTextNode
I Using ScanCriteria I 317
Sub TestScanFilterB ()
Dim myEnum As ElementEnumerator
Dim myFilter As New ElementScanCriteria
Dim ElementCounter As Long
myFilter . ExcludeAllTypes
my Fi lter. lncludeType msdEle mentTypeText
myFilter . lnc l udeType msdEle mentTypeTextNode
Set myEnum = ActiveModelReference.Scan(myFilter)
While myEnum . MoveNext
ElementCou nte r = ElementCounter + 1
Wend
MsgB ox ElementCoun ter & " elements found. "
End Sub
Now, myEnum only contains Text and TextNode elements.
Let's build on TestScanFi 1terB by adding a filter for a specific level.
Before we look for a specific Level, we must first exclude all levels. If we
miss this critical step, we will be retrieving all levels.
Sub TestScanFilterC ()
Dim myEnum As ElementEnumerator
Dim myFilter As New ElementScanCriteria
Dim ElementCounter As Long
myFilter . ExcludeAl l Types
myFilter . ExcludeAllLevels
myFi l ter .l ncludeType msdElementTypeText
myFilter .l ncludeType msdElementType TextNode
318 I Chapter 16: Searching In Files I
my Fi 1t e r . In c 1 ude Lev e 1 Act i ve Des i 9n Fi 1e . Leve l s ( " SI DEWALK" )
Se t myEnum = Act i ve Mode lR ef e r ence.Scan(myF i lter)
While myEnum.MoveNext
ElementCounter = ElementCounter + 1
Wend
MsgBox El ementCounter & " el ements found ."
End Sub
Let's look over the macro "ScanFilterc". What is being counted here?
Text elements and TextNode elements on Level "SIDEWALK'~
Sub TestScanFilterO ( )
Di m myEnum As ElementEnumerator
Dim myFil t er As New Ele mentScanCr i teria
Dim ElementCounter As Long
myFilter . ExcludeA l lTypes
myFilter.ExcludeAllLevels
myFilter.ExcludeAllColors
myFilter.IncludeType msdElementTypeText
myFilter.IncludeType msdElementTypeTextNode
myFilter.IncludeLevel ActiveDesignFile.Levels( "SIDEWALK " )
myFilter . IncludeCo l or 4
Set myEnum = ActiveModelReference.Scan(myFilter)
While myEnum.MoveNext
ElementCounter = ElementCounter + 1
Wend
MsgB ox ElementC ounter & " elements found."
End Sub
We have added one more scan criteria. In addition to looking at the
element type and level, we are now looking at the color.
If we know a color's index in the document's color table, we can specify
it as shown above. Let's look at the next example where we specify an
RGB color value to filter for a specific color. We will also add one more
item in our scan criteria. Let's add a Linestyle criteria.
Sub TestScanFilterF ()
Dim myEnum As ElementEnumerator
Di m myFi l ter As New ElementScanCr i teria
Dim ElementCounter As Long
Dim myColorTable As ColorTable
Dim myColor As Long
Set myColorTable = ActiveDes i gnFile . Extra ct Co l orTa ble
I Using ScanCriteria I 319
Sub TestScanFilterG ()
Dim myEnum As Ele mentEnu merator
Dim myFilter As New ElementScanCriteria
Dim El ementCounter As Long
Dim my ColorTa ble As ColorTable
Dim myCol or As Long
Set myColorTable = ActiveDesignFile.ExtractColorTable
myColor = myColorTable .Fin dClosestColor(RGB(192. 192. 192))
myF il ter.ExcludeAll Types
myFilter.ExcludeAllLevels
my Fi 1t e r . Ex c 1 ude All Color s
myFilter .E xcludeAllL i neStyles
myFilter.ExcludeAllClasses
myFilter.lncludeType msdElementTypeLineString
myFilter.lncludeLineStyle ActiveDesignFile . LineStyles("( Hidden )")
my Fi 1t e r . Inc 1udeL eve 1 Act i ve Des i 9n Fi 1e . Level s ( " SID EWALK" )
myFilter . lncludeColor myColor - 1
myFilter. IncludeClass msdElementClassPrimary
Set myEnum = ActiveModelReference.Scan(myFilter)
While myEnum.MoveNext
ElementCounter = El ementCounter + 1
Wend
MsgBox ElementCounter & " elements found. "
End Sub
320 I Chapter 16: Searching In Files I
N ow we are adding the "Class" to our scan criteria.
Thus far we have excluded everything from our criteria and added in
only the criteria we wanted. When we 'ExcludeAllLevels', the number of
levels we exclude varies from file to file.
N ow, let's look at each of the levels in our design file. One specific level
will not be added to our scan criteria and everything else will be added.
Su b TestScanFilterH ()
Dim myEnum As ElementEnumerator
Dim my Fi lte r As New El ement ScanCrit eri a
Di m my Level As Level
Dim El emen t Coun t e r As Long
myFilter.ExcludeAllLevels
For Eac h myLevel In ActiveDes ig nF il e.Levels
Select Case UCase( myLeve l. Na me)
Case "SIDEWALK "
Case Else
myFilter.IncludeLevel myLevel
End Select
Next
Set myEnum = ActiveModelReference . Scan(myFilter)
While myEnum.MoveNext
ElementCounter = ElementC ounter + 1
Wend
MsgBox ElementCounter & " eleme nt s found. "
End Sub
When dealing with our ElementScanCriteria object, everything is
within the bounds of the criteria. Since we don't have the option to
remove a specific element type or level, etc., in the above example, we
remove all levels and then add back those levels that meet our criteria. In
the above example, we are adding all levels except for the "SIDEWALK"
level.
I Multiple Combinations of Criteria I 321
myFi1ter.Reset
myFi 1ter.Exc 1udeA11Ty pes
myFi 1ter . Exc1udeA 11 Leve 1s
myFi 1ter .I nc1udeType msd E1ementTypeText
myFi 1ter . I nc1 udeLeve1 Ac t i veDesi gnFi 1e . Level s ( "MARKS " )
Set myEnum = Act i veMode1Reference . Scan(myFi1ter)
Wh il e myEnum . MoveNext
Set myE1em = myEnum . Current
myCo11ect i on.Add myE1em
Wend
MsgBox myCo11ection . Co unt & " el ements found ."
End Sub
This is another way to accomplish the same goal. We apply two separate
criteria. As we move through each enumerator, we add the element in
the enumerator to a custom collection. This allows us to work with a
single collection of objects after each combination of criteria is applied.
I Multiple Combinations of Criteria I 323
Elementcache!ElemenlCac I
Cache Index 18 Long
Class msdElemenlClassPrimary MsdElemenlClass
Color 0 Long
DateLastModified #9120120055:26:39 PM# Date
FilePosrtion 4000017 Long
GraphicGroup 0 Long
HasAnyTags False 800lean
Adding a watch to InDisplaySet True 800lean
Here is one more way to accomplish the same task. We are going to
create a named group and then add the objects we find to the named
group.
Sub TestScanFilterN()
Dim myEnu m As ElementE numerator
Dim myFilter As New Ele mentScanC riteria
Dim myGroup As NamedGroupElement
Dim myRange As Range3d
Set myGroup = ActiveModelReference.AddNewNamedGroup("GroupC")
myRange. Low.X = 1: myRange.Low.Y = 1: myRange.Low.Z = 0
myRange . High.X = 3: myRange.High.Y = 3: myRange.H i gh.Z = 0
myFilter . lncludeOnlyWithinRange myRange
Set myEnum = ActiveModelReference.Scan(myFilter)
While myEnum.MoveNext
myGroup.AddMember myEnum.Current
We nd
myGroup. Rewrite
MsgBox myGroup.MembersCount & " el ements found."
End Sub
The ability to scan a file from within only a specific area is very
powerfuL We may look for elements surrounding a point selected by the
user, for example. Or we may scan for elements surrounding cells with a
specific name. The range we specify is 3D so we can provide a Low.Z
and a High.Z value if we are working on 3D files.
I Review I 327
REVIEW
Each file in MicroStation is composed of many objects. Some of these
are visible, others are not. Levels, for example, are not graphical
elements but are still very important.
We should be careful when we scan our files. If we scan with the intent
to create new geometry, it is possible to create a problem for ourselves.
For example, if we are scanning a file for lines and are drawing new lines
over old ones, the new lines may be added to our ScanCriteria and we
could end up in an endless loop.
This chapter covered scanning MicroStation files with pre-defined
criteria. In the next chapter, a user makes selections in MicroStation and
then has our code manipulate the selection.
328 I Chapter 16: Searching In Files I
17 Interactive Modification
In this chapter:
[8 Giving users feedback and information
[8 Working with selection sets
[8 Getting user input
[8 Using the send command
[8 Employing modeless dialog boxes
[8 Applying some real-world applications
[8 Interacting with MDL applications
329
330 I Chapter 17: Interactive Modification I
These areas are called the command, prompt, and status areas.
Command Prompt Status
Place SmartLine > Enter first verte~ 11"0-File [C:\Microstation VBA\docs\chapter17a.dgnj saved
Sub TestShowCommand ()
ShowC om man d "Draw a Li ne "
ShowPrompt "Select First Po i nt :"
ShowSta tu s "Draw Line by selec t ing tw o pO i nt s . "
En d Sub
Three methods are used to show the text we want to display in the
command, prompt, and status areas of MicroStation. Even though the
user can change the size of the command/prompt area, make sure that
commands and prompts are visible without requiring users to stretch
the area wider. Commands and prompts are not meant to provide
comprehensive instructions, but rather, general guidelines.
1D ~ Q i~ I ~ ~ ft II<) 00 ItQ i ?
11J~ 1 ~:"Ij
, •
;... : C§J •
2} .. :. =
o
]JJ',
J.
A!- .
5',
.I. ~
.GJ~ E- •
7~
~-,
Sub TestShowTempMessageCenter ()
ShowTempMessage msdStatusBarAre aMi dd l e. "Changes made to file :" , _
"Changes were made to t he fi l e C: \testa.dgn. " &
"These changes were made by the macro " &
"" "TestS howTempMessageCenter ""."
End Sub
332 I Chapter 17: Interactive Modification I
Message Details
Changes were made to the me C:\testa,dgn These changes
were made by the macro "T estShow TempMessageCenter",
The next feedback method we will look at is the ShowErr or method. The
text we supply with this method displays in the command/prompt area.
Sub TestShowError()
ShowError "Selection of Cell Fai led ,"
End Sub
Selection of Cell Failed. Ire No Eiements Found
Sub TestSelectionSetA ()
Di m myE l ement As El ement
Dim myElemEnum As ElementEnumerator
Set myElemEnum = Act i veModelReference , GetSelectedElements
While myElemEnum.MoveNext
Set myElement = myElem Enum , Current
myE l ement .L evel = ActiveModelReference.Levels( _
"A-FURN-FREE")
Wend
End Sub
We used the ElementEnumerator in a previous chapter. In this example,
we get the selected elements and change the level of each element one-
by-one. Let's look carefully at the code. Are we missing anything?
myElement.Rewrite
Wend
End Sub
If we do not rewrite the element to the design file , element
modifications are not persistent. This is critical. You could spend a great
deal of time debugging code only to find that changes made to elements
are not reflected in your files. Any changes made to elements in files
must be rewritten back to the file or they are not permanent. This is by
design.
Sub TestSelectionSetC ( )
Dim mySettings As Settings
Se t mySettings = Application . ActiveSettings
If MsgB ox( "Change Select i on t o Colo r" & myS ett i ngs.C ol or & " ?", _
vbYesNo) = vbYes Then
Dim myElement As El ement
Dim myElemEnum As ElementEnumerator
Set myElemEnum = ActiveModelRefere nce . GetSelectedElements
While myElemEnum.MoveNext
Set myElement = myElemEnum.Current
myElement . Color = mySettings . Color
myElement.Rewr i te
Wend
End If
End Sub
TestS el ecti onS etC changes all selected
elements to the active color in MicroStation if
Change Selection to Color O? the user clicks on the Yes button in the
MessageBox. We are using the same
methodology going through each of the
elements in the ElementEnumerator.
334 I Chapter 17: Interactive Modification I
Sub TestCadlnputA ()
Di m myCIO As CadlnputOueue
Dim myCI M As CadlnputMessage
Dim I As Long
Set myCIO = CadlnputOueue
For I = 1 To 10
Set myC IM = myCIO.Getlnput
Debug.Print myCIM . lnputType
Ne xt I
End Sub
In the above example, we capture ten user interactions and print the
InputType to the Immediate Window. The main thing we want to see
with this example is the mechanics of how to use the CadInputQueue
and the CadInputMessage.
Let's make a couple of modifications to the above example to capture
only point selections.
Sub TestCadlnputB ()
Dim myC IO As CadlnputOueue
Di m myC IM As Cad l nputMessage
Dim I As Long
Dim pt3Select i on As Point3d
Set myCIO = CadlnputOueue
For I = 1 To 10
Set myC I ivi = [IIYC 10. Ge LI nput (msdCad I nputTypeData Poi nt)
pt3Selection = myCIM.Point
Debug.Print pt3Selection.X & ", " & pt3Selection.Y
Next I
End Sub
I Getting User Input I 335
Sub TestCadlnputC()
Dim myCIO As CadlnputOueue
Dim myCIM As CadlnputMessage
Dim I As Long
Dim pt3Selection As Point3d
Set myCIO = CadlnputOueue
Fo r I = 1 To 10
Set myCIM = myCIO . Getlnput(msdCadlnputTypeDataPoint, _
msdCadlnputTypeReset)
Select Case myCIM .l nputType
Case msdCadlnputTypeDataPoint
pt3Selection = myCIM.Point
Debug . Pr i nt pt3Selection.X & " " & pt3Selection.Y
Case msdCadlnputTypeReset
Exit For
End Select
Next I
End Sub
Now, our macro captures up to ten input points or until a reset is
initiated by the user. We use Ex it For to exit out of the loop when a reset
is detected.
We have introduced DataPoint and Reset input types, so what other
types are available to us?
msdCadlnputTypeCommand 1
msdCadlnputTypeReset = 2
msdCadlnputTypeOataPoint 3
msdCadlnputTypeKeyin = 4
msdCadlnputTypeAny = 5
msdCadlnputTypeUnassignedCB 6
336 I Chapter 17: Interactive Modification I
When we begin capturing input using the CadlnputQueue, our program
listens to each of the inputs, then the results of the inputs is entirely in
the hands of our program. For example, if we begin capturing inputs,
selecting a command from a toolbar sends the command information to
our queue but MicroStation does not begin acting on the command
immediately.
This pro cedure captures ten inputs or captures until a reset is detected.
The resu lts of runn ing this procedure with a variety of inputs.
Points
The points selected gives us much more than the X, Y, and Z locations in
M icroStation. We also see in which view the point was selected and the
screen coordinates in X, Y, and Z when the point was selected. The
screen X, Y, and Z could be useful for more advanced work such as
displaying graphical information in MicroStation using the Windows
API.
Commands
Whenever a legitimate MicroStation command is initiated and we are
listening using the Cad Input Queue, the input comes across as a
command. This is the case no matter whether the command was
initiated using menus, toolbars, or the Keyin window.
Keyin
If the Keyin window is used to enter a legitimate command, the input is
registered as a command and not a keyin. When something is entered in
the Keyin window that does not result in a legitimate command, it is
registered as a keyin. The example above demonstrates this when "bogus
keyin" was entered into the Keyin window.
Reset
The Reset Input is triggered when the user initiates a reset. For example,
clicking the right mouse button initiates a reset when the user is asked to
select a point.
better yet, running the code, reveals that although the user can select
two points and a line is drawn between the points, the user has no way
of knowing what to do or what the results of the actions will be. Let's use
our knowledge of ShowCommand and ShowPrompt to make the macro more
user friendly.
Sub TestCadlnputF( )
Dim myCIO As CadlnputOueue
Dim myCIM As CadlnputMessage
Dim pt3Start As Point3d
Dim pt3End As Point3d
Dim myLine As LineElement
Set myCIO = CadlnputOueue
ShowCommand "Two-Point Line"
Show Prompt "Select First Point:"
Set myCIM = myCIO . Getlnput(msdCadlnputTypeDataPoint . _
msdCadlnputTypeReset)
Select Case myCIM.lnputType
Case msdCadlnputTypeReset
ShowPrompt ""
ShowCommand ""
ShowSta t us "Two-Point Line Reset."
Exit Sub
Case msdCadlnputTypeDataPoint
pt3Start = myCIM.Point
En d Select
ShowPrompt "Select Second Point:"
Set myC IM = myC IO.Getlnput(msdCa dlnputTypeDataPoint . _
msdCadlnputTypeReset)
Select Case myCIM . lnputType
Case msdCadlnputTypeReset
ShowPrompt ""
ShowCommand ""
ShowStatus "Two-Point Line Reset ."
Ex it Sub
Case msdC adlnputTypeDataPoint
pt3End = myC IM . Point
End Select
Set myL ine = CreateLineElementZ(Nothing . pt3Start . pt3End)
ActiveModelReference . AddElement myLine
myLine.Redraw
340 I Chapter 17: Interactive Modification I
ShowPrompt ""
ShowCommand ""
ShowStatus "Two-Point Line Drawn."
End Sub
Now, when this macro is run, the user is prompted at each step.
The CadlnputQueue can be used for more than just capturing user
input. We can use it to execute commands as well. Here is one example:
Sub TestCadlnputH ()
Dim myCIO As CadlnputOueue
Dim myCIM As CadInputMessage
Dim pt3Start As Point3d
Dim pt3End As Point3d
Di m myL i ne As LineElement
Dim SelElems() As Element
Set myCIO CadInputOueue
Set myCIM = myCIO.GetInput(msdCadlnputTypeDataPoint,
msdCadInputTypeReset)
Select Case myCIM.InputType
Case msdCadInputTypeReset
Exit Sub
Case msdCadI nputTypeDataPoint
pt3Start = myCIM.point
End Select
Set myCIM = myCIO.GetInput(msdCadInputTypeDataPoint,
msdCadInputTypeReset)
Select Case myCIM.lnputType
Case msdCadInputTypeReset
Ex it Sub
Case msdCadInputTypeDataPoint
pt3End = myCIM.point
End Select
CadInputOueue.SendDragPoints pt3Start, pt3End
SelElems =
ActiveModelReference . GetSelectedElements.BuildArrayFr omC ontent s
If MsgBox("Are you sure you want to delete" &
UBound(SelElems) + 1 & " Elements?", vbYesNo) _
= vbYes Then
In this example we used the selected points with the Se ndD ragP oi nts
method of the CadInputQueue object to effectively select the elements
within the window generated by the two points. We get a count of the
number of elements selected and ask the user to verify that the elements
are to be deleted through a MessageBox with Yes and No buttons. If the
user says "Yes", we delete the selected elements by sending a Command
of "DELETE".
This allows the user to select two points and delete the window between
the two points. But we must ask ourselves, does it work well? After the
first point is selected, we cannot see where the point had been selected.
It would be better if we could see the first selection point like when we
draw a line.
The next function allows the user to select two points. After the first
point is selected, we see the same graphical interface from MicroStation,
as we when drawing a line using standard MicroStation commands,
until the second point is selected. This function then returns the two
points.
Sub TestCadlnputJ ()
On Err or GoTo err hnd
Di m sel Pt s( ) As Point3d
selPts = Poi nt sBy Li ne
CadlnputOueue . SendReset
CommandState.StartDefaultCommand
Debug.Pr i nt selPts(O).x & " , " & selPts ( O) .Y & ", " & selPts(O).Z
Debug . Print se l Pts(l) . X & ", " & selPts(l) . Y & ", " & selPts(l).Z
Ex i t Sub
er r hnd :
CadlnputOueue . SendReset
CommandState.StartDefaultCommand
Selec t Case Er r.N umbe r
Case -12345
'Start Point not selected
MsgBox "Start Point not selected. ", vbCritica l
Case -12346
' End Point not selected
MsgBox "End Point not selected . " , vbCritical
I Some Real-World Applications I 343
End Selec t
End Sub
We use Poi ntsByL i ne to get two points. Notice the SendReset and
StartOefaul tCommand calls. This resets the Place Line command which
started when we called "PointsByLine". If the user selects the two points
as requested, we display the coordinates of the points in the Immediate
Window. If the user does not select one of the points, we know which
point selection was aborted based on the error raised in the
PointsByLine Function.
Here is a more practical application of our new Poi ntsByL i ne function:
Sub TestCadlnputK ()
On Error GoTo errhnd
Dim selPts() As Point3d
Dim pt3TextPt As Point3d
Dim my Te xt As TextElement
Dim rotMatrix As Ma t rix3d
selPts = PointsByLine
CadlnputOueue.SendReset
CommandState.StartDefaultCommand
Set myText = CreateTe xtEleme ntl ( Nothing. "St a rt " . se lPt s (O) . r ot Matrix )
ActiveModelReference . AddElement myText
Set myText = CreateTextElement1(Nothing. "En d". se l Pts(ll . rotMatrix)
ActiveModelReference .A ddElement myText
pt3TextPt . X selPts(O) .X + (selPts(l).X - selPts(O) . X) /2
pt3 Textpt.Y = se l Pts(O) . Y + (se l Pts(l).Y - sel Pts(O)'Y) /2
pt3TextPt.Z = selPts(O).Z + (selPts(l) . Z - selPts(O) . Z) / 2
Set myText = CreateTextElementl(Nothing. "Mid". pt3TextPt. rotMatrix)
ActiveModelReference.AddElement myText
Ex i t Sub
errhnd:
Cad ln putQue ue . SendReset
Comma ndState . StartDefaultCommand
Select Case Err.Number
Case -12345
' Start Point not se lected
MsgBox "Start Point not selected ." , vbCrit i cal
Case -12346
' End Point not selected
MsgBox "End Point not selected. " . vbCritical
344 I Chapter 17: Interactive Modification I
End Select
End Sub
The framework is the same as the previous example. We use our new
Poi ntsByL i ne function to get two points while simulating the Place Line
command. Once we get the points, we use them to place three new text
elements in our file. "Start", "End" and "Mid" are placed at the start
point, the end point, and the calculated mid point.
Here is what it
looks like in
Mi croStation :
Start
errhnd:
CadlnputOueue.SendReset
CommandState . StartDefaultCommand
Select Case Err .Nu mber
Case -12345
'Star t Poi nt not selected
MsgBox "Start Point not selected .". vbCritical
Case - 12346
'E nd Point not selected
MsgBox "End Point not selected .... vbCritical
End Select
End Sub
346 I Chapter 17: Inte ractive Modification I
: li t~
TestC adl nputL does not do anything fancy. It just displays the points
selected in the Immediate Window. Let's make better use of
Po i nts ByRec tan gl e by using the selected points as part of a scan criteria
in selecting cells in a file.
Sub TestCadlnputM ()
On Err or GoTo er rhn d
Dim sel Pts() As Po i nt3d
Di m Li nePt s(O To 1) As Point 3d
Dim LineElem As LineElement
Dim myESC As New ElementScanCriteria
Dim myRange As Range3d
Di m myElemEnum As El ement Enumerator
Dim myElem As Element
Dim FFile As Long
Dim myCellHeader As Cell Element
selPts = Po i ntsByRectangle
Cad I nputOueue.SendReset
CommandState . StartDefaultCommand
myRange = Range3dFromPoint3dPoint3d(selPts(O) , selPts(l))
myESC . ExcludeAllTypes
myESC.IncludeType msdElementTypeCellHeader
myESC . Incl udeOnlyW i thi nRange myRange
Set myElem Enum = ActiveModelReference.Scan(myESC)
I Some Real -World Applications I 347
FFile = FreeF i le
Open "C: \MicroStation VBA\CellExport.txt" For Output As #FFile
Pr int #FFile, ActiveDesignFile.Name
While myElemEnum.MoveNext
Set myElem = myElemEnum.Currert
Set myCellHeader = myElem
Print #FFile, myCellHeader.Name & vbTab &
myCellHeader . Origin.X & vbTab &
myCellHeader .Origin.Y & vbTab &
myCellHeader.Origin.Z
Wend
Close #FFile
Exit Sub
errhnd:
CadlnputQueue.SendReset
CommandState.StartDefaultCommand
Select Case Err.Number
Case -12345
'Start Point not selected
MsgBox "Start Point not selected. " , vbCritical
Case -12346
' End Point not selected
MsgBox " End Point not selected .", vbCritical
End Select
End Sub
This macro writes the names and locations of cells in the active model
reference that fit within the selected rectangle.
The results of the macro differ from file to file and from selection to
selection. If fewer cells are selected inside the rectangle, fewer cells will
be output to the text file.
348 I Chapter 17: Interactive Mod ification I
USING SENOCOMMANO
Thus far we have used SendCommand with "DELETE", "PLACE LINE",
and "PLACE BLOCK': Even though these commands may look familiar
to some readers, they may be fore ign to others. Each time a menu item is
selected or toolbar button clicked, a command is issued to MicroStation.
How do we know what these commands are? Good question.
The MicroStation VBA macro recorder can help us to discover
command names and how they are used. Let's try recording a few
macros to demonstrate this.
1 From the VBA Project Manager, select the VBA Project in which we
are currently working and then click the record button.
Sub Macrol c)
Dim s tartPo in t As Point 3d
Dim pOi nt As Poi nt3d. point2 As Po i nt3d
DiTi lngTemp As Long
Start a command
CadInputOueue . SendCommand "CGPLACE LINE CONSTRAINED ·
Sub Macro2 ()
Dim startPoint As Point3d
Dim point As Point3d, point2 As Point3d
Dim lngTemp As Long
Start a command
CadlnputOueue.SendCommand "PLACE BLOCK ICON"
Sub Macro2_modifiedA ()
Dim point As PoiflL3d
CadlnputOueue.SendCommand "PLACE BLOCK ICON"
point.X 0
point.Y = 0
I Using SendCommand I 351
point.Z = 0
Ca dln putOueue .S endData Poi nt po i nt . 1
po int.X = point . X + 2. 5
point . Y = pOint.Y - 0 . 75
CadlnputOueue . SendDataPoint pOint.
CommandState . StartDefaultCommand
End Sub
In this example, we are basing the second point on the first point.
Instead of entering hard-coded coordinates, the second point is relative
to the first point. However, even though the placement of the second
point is relative to the first point, the first point is hard-coded. Let's
make a few more modifications.
Sub TestCadlnputN ()
Di m myCIO As Cad l nputOueue
Dim myC IM As CadlnputMessage
Dim I As Long
Set myCIO = CadlnputOueue
For I = 1 To 10
Set myCIM = myCIO.Getlnput(msdCadlnputTypeCommand)
352 I Chapter 17: Interactive Modification I
Debug . Print myCIM . CommandKeyin
Next I
End Sub
TestCadlnputN captures ten
commands. This is
CGPLACE LINE CONSTRAINED
different from recording PLACE BLOCK ICON
CGPLACE CIRCLE ICON
macros in that we do not HATCH ICON
get all of the other input, Attach Tags
WORDPROCESSOR PLACE TEXT ICON
such as point selections, PLACE CELL ICON
etc. The only thing we MEASURE DISTANCE ICON
DIMCREATE ELEMENT
capture is the command PLACE FENCE ICON
name.
One additional method of determining command names should be
mentioned.
L~~_~!:~~~ _________________.___________________________-' BJ ~
ri!~
digilizer palette
dimcreale ~I parlicielrace
dimension plol
dims lyle popsel
displaysel
dialog openfile
dialog drawing scale open
dialog dr awingscale
delele
erase
bogus keyin
frmMatchProperties.frm
The first form,
"frmMatchProperties.
frm", looks like this:
r :source Element:~..,..-,--,-,--,-~ ~-:-:t !:-: De,stination Element(~): ~:-:-:- ·t
The form
simple enough. We
looks
:: Seled I
i: I: Change Current Selection :
buttons, a couple of :: ,. ~ : ll p
frames, a handful of ILineweight r I ,': h-,:- .' .' , : ,: ,: ,: ,:::,J.
check boxes, a label,
and four text boxes. Close L'
: :i: : :; :: .:.: '., .
Desired Functionality
1 The user can select a Source element in MicroStation. After the
element is selected, the Select button is clicked and four properties
are extracted from the selected element: level, color, linestyle, and
lineweight.
2 The user can select which of the properties from the source element
are to be changed in the Destination Elements.
3 The user can select any number of elements in MicroStation to be
modified based on the selected properties of the source element.
This sounds simple enough. Let's get started. Even though the form can
be imported from the CD, we will discuss the entire process of creating
the form.
The first thing we do is place the controls. As we work with an interface,
we will find ourselves resizing and moving the controls to make our
interface flow nicely for the user. Captions (when available) can be
modified immediately after we add each control.
Naming the controls is the next step. Here are the names of the controls
with which we will be interacting:
[E frmMatchProperties
[E btnSelectSource
[E chkLevel
[E txtLevel
[E chkColor
[E txtColor
[E chkLinestyle
[E txtLinestyle
[E chkLineweight
[E txtLineweight
[E btnChange
[E IblCount
~ btnClose
[E fraSource
[E fraDestination
I Modeless Dialog Boxes I 355
Control Properties
1 The Locked property of each TextBox should be "True". We do not
want the user arbitrarily typing in values that do not work. The text
boxes will be populated by the source element's properties.
2 The Alignment property of each CheckBox should be
"fmAlignmentLeft': This places the caption of the CheckBox on the
left of the CheckBox.
3 The ControlTipText of the Select CommandButton is "Click Here to
make the current selection the source elemenf'.
4 The ControlTipText of the "Change Current Selection"
CommandButton should be "Click Here to modify the current
selection to match the selected properties from the Source element:'.
5 The ControlTipText of the "Close" CommandButton should be
"Click Here to Close the VBA Match Properties Program:'
Later we will add code to display this form as modeless. This means the
user will be able to interact with MicroStation even though the form is
displayed. This is important to keep in mind as we look at the code
behind the controls.
Option Explicit
Dim elemSource As Element
356 I Chapter 17: Interactive Modification I
Select Button
We can only use one element as the source element. When the user
clicks the Select button, the first thing we need to do is to discover how
many elements have been selected. If only one element has been
selected, we can continue. Otherwise, we will display one of two
MessageBoxes: one MessageBox if nothing was selected or a second if
more than one element was selected.
If only one element is selected, do the following:
1 Get the level (if a level is assigned to the element). The level name is
placed in the appropriate text box.
2 Get the color and display the number in the appropriate TextBox
and change the TextBox's BackColor property to match the color of
the source element.
3 Get and place the linestyle property.
4 Get and place the lineweight property.
Now, let's look at the code behind the btnSelectSource_Click event:
Close Button
The Close button unloads the Form.
I Providing User Feedback and Information I 359
UserForm Initialize
We need to discuss two additional events. The first of these is the
UserForm Initialize event. This event is triggered as the form is about to
be displayed.
UserForm QueryClose
The QueryClose event is triggered just before the fo rm is terminated.
This event allows us to perform clean up operations. It also tells us how
the form was asked to close. The CloseMode parameter gives us one of
four values (which have corresponding constants).
IB vbFormControlMenu =0
IB vbFormCode =1
IB vbApp Windows =2
IB vbAppTaskManager =3
For more information on what each of these values mean, look up
"QueryClose Constants" in the Microsoft VBA help.
I Providing User Feedback and Information I 361
In this program we are not concerned with how the form is closed, only
that it is closing.
~ '-'''-"'
- Destination Element(s)
Notice the Command
and Prompt areas at the "' Select
I Change Current Selection
II
bottom. Level ~ f"l, ,I, oElement(s) modified,
r-" '-'-', IClick Here to make the current selection the "Source" Element.
I:::' _~B
The Match Properties
Program is simple and
straightforward. We
allow the user to make
Close
,
I .-
frmAlignText.frm
The next form we will import into
our VBA project is the
frmAlignTextfrm file. This form
allows the user to perform text
I~; ' I 0
~
M
Desired Functionality
~ Selected Text can be aligned Horizontally to the selected or
entered "X" value.
~ Text can be aligned Left, Center, or Right.
~ Text can be distributed evenly vertically so equal spacing exists
between each text element.
[B Only Text elements can be used, not Text Nodes.
I Providing User Feedback and Information I 363
Frames, command buttons, labels, and text boxes are used in this
project. Once again, you can import the fo rm from the CD
accompanying this book, but we will discuss building this form as
though we were starting with nothing.
Control Placement
Place the controls as shown. The Base Point frame and Horizontal
Alignment frames contain their respective controls and the "Distribute
Vertically" button is by itself. If a "Distribute Horizontally" button
existed, we would place both "Distribute" buttons in their own frame.
After placing the controls, change captions and text properties as shown
above.
Control Names
[8 fraBasePoint
[8 fraHoriAlign
[8 btnPickBasePoint
[8 txtX
[8 txtY
[8 btnAlignLeft
[8 btnAlignCenter
[8 btnAlignRight
[8 btnDistribute Vert
Pick Button
The code in the "Pick" button's click event allows the user to select a
point in MicroStation. The selected point's X and Y components then
display in the text boxes.
X and Y TextBoxes
The X and Y TextBoxes are populated with values from points selected
by the user through the Pick Button just discussed. In addition to
picking the point, we want to allow the user to hand-enter X and Y
values. Picking points is nice because we know that the user cannot
select an invalid point in MicroStation. Allowing data entry can cause
problems if we are not careful. What happens, for instance, if the user
enters "somewhere around 4.5" in the TextBox? This entry would be far
from the numeric value we are counting on. One way to limit the user's
entry in these text boxes is to make use of the KeyPress event.
Enu m AlignMode
msvbaAlignModeLeft 1
msvbaA l ignModeCenter 2
msvbaAlignModeRight = 3
End Enum
Now when we declare our procedure to align the selected text, it looks
like this:
I
AlignSelecte d
End AlignSelected(lEleJlIl 0 i0.~y'~~~l i~ ~·~~~~¢'~~i~i 11!lIIModeLeft])
o msvbaAli gnModeLeft
Pci vate Su b btnA 0 msvbaAlignModeR ight (ByVal But
Enumerations help us make sure that the param eter we are providing is
legitimate and make it easier to program because we are shown our
options for the parameter.
One additional declaration needs to be added to the General
Declarations area of our form:
Degrees of Complexity
There are three degrees of complexity in this program. The degrees and
their tasks are as follows:
Low: Pick a point, place X and Y components into TextBoxes.
Medium: Align selected Text Elements Left, Center, or Right.
High: Vertically Distribute selected Text Elements even ly.
4. Note 4. ·· .'.
we are faced with the task of making the text
look nice vertically. The spacing between
Note 1 and Note2 is tight, whereas the spacing between Note2 and
Note3 is loose (as it is between Note 3 and Note 4). We want the spacing
between each of these text elements to be the same. It is a simple task but
a number of considerations must be made before continuing.
I Providing User Feedback and Information I 369
1 After the user selects the text, we want even spacing between the top
and bottom elements without those elements moving.
2 On the screen it is readily apparent which element is on top and
which is on the bottom. But when we look at the selection in code,
we do not know which element is on top and which is on the
bottom.
3 On the screen we can see the proper order. But when we look at the
selection in code, we do not know the top-down order of the text
elements.
We will create distinct functions to accomplish each of the following
tasks:
[B Discover the minimum and maximum points of the selected
text elements.
[B Determine the vertical order in which the text elements appear.
pt3BoundPt( UBound(pt3BoundPt)) = _
my Tex tEl em.Bo un dary . Hi gh
ReDim Pr eserve ln gElemID ( UBound ( lngElemID ) + 1) As
DLong
ReDim Preserve pt3Bo~ndPt(UBound(pt3BoJndPt) + 1) As
Poi nt3d
End If
End Select
Next I
ReDim Preserve lngE l emID(UBound(lngElem I D) - 1) As Dlong
boolMadeChange = True
Whi l e boo lM adeChange = Tr ue
boolMadeCha nge = False
For I = lBound(lngE l emID) To UBound(lngE l emID) - 1
If pt3BoundPt(I + l).Y > pt3BoundPt( I ) . Y Then
tmpID = lngElemID(I)
tmpPt = pt3BoundPt(I)
lngElemID(I) = lngE l emID(I + 1 )
pt3BoundPt(I) = pt3BoundPt(I + 1)
l ngElemID(I + 1) = tmpID
pt3BoundPt(I + 1) = tmpPt
boolMadeChange = True
End If
Next I
Wend
Dim Elemsln() As El ement
ReDim ElemsIn(O To UBound(lngElemID))
For I = lBound(lngElemID) To UBound(lngElemID)
Set Elemsln(I) = ActiveDesignFile.GetEleme ntByID(lngElemID ( I ))
Next I
SortE l ementsVertically = Elems I n
End Function
There is a lot of code to look at here. After we divide it into four little
chunks, it becomes easier to understand.
Variabl e Declaration
Dim I As l ong
Dim boolMadeChange As Boolean
Dim lngElemID() As Dl ong
Dim pt3BoundPt () As Poi nt3d
Dim myTextE l em As TextEleme nt
372 I Chapter 17: Interactive Modification I
Dim myTex t Elem2 As TextElem ent
Dim t mpI D As DLong
Dim tmpPt As Point3d
Two variables are declared as dynamic arrays (by using the empty
parenthesis). Dynamic arrays can change in size without losing their
values. Other variables are declared as well.
Bubble Sorting
boolMadeChange = True
While boolMadeChange = True
boolMadeChange = False
For I = LBound (lngE lemID ) To UBound(lng Elem ID) - 1
If pt3BoundPt(I + 1).Y > pt3Bou'ldPt(I).Y Then
tmpID = lngElem ID(I )
tmpPt = pt3BoundPt(I)
lngElemID(I) = lngElemID (I + 1)
pt3BoundPt(I) = pt3BoundPt(I + 1)
lngElemID(I + 1) = tmpID
pt3 Boun dP t(I + 1 ) = tmpPt
bool Mad eChange = Tr ue
End If
Next I
Wend
We have discussed bubble sorting previously. We are looking at the Y
values of two points. We want the highest Y values to be at the top of the
list. So, if a Y value lower down on the list is higher than the Y value just
above it in the list, we switch the two. When a switch is made we set the
variable boo lMadeChange to True. This means we will run through the
array again. We continue running through the array until a switch is not
made. When we find we have not made a switch, the sorting is complete.
so r tElems = Sor t Elem en t sV e r ti cal l y(msd Ele me ntTy peTe xt , myE l ems)
For I = LBound(s ort Elems ) To UBound( sor tEl ems )
Set myTextElem = sortElems(I)
myTextElem . Move Po'rt3dFromXY(O, tvlyPts(O).Y -
dblSpacePerElement * I - myTextElem . Boundary.High.Y)
myTextElem . Rewrite
myTextElem.Redraw
Next I
End If
End Sub
A close look at the above code reveals the use of the three functions we
just finished discussing. GetMi nM axY, GetSe 1ectedCount, and
So r tE 1emen ts Vert i ca11y are used. After we have sorted the elements
vertically, we move them so that they are spaced evenly.
End Sub
frmExportElements.frm
The frmExportElements.frm User
Form accomplishes a simple task:
it exports elements on specific
Levels ..
levels to a new design file.
The task for this project is simple.
The interface reflects this. We
need to allow the user to select
any number of levels, enter a file
name for the new file to be
created, and then click on the
Export button.
Control Names
.. . . . .
... ..
File Name : .
IB 1st Levels
IB txtFileName !:: :
Export f
IB btnExport
Control Properties
IB IstLevels property MultiSelect is set to 2 -
fmMultiSelectExtended
IB IstLevels property ListStyle property is set to 1 -
fmListStyleOption
When this program begins executing, we need to get the names of all
levels of the active design file into the list box. This is very easy to do.
Because we are not given level names in alphabetical order, we will
employ a bubble sort to put them into the list box in alphabetical order.
File Name
I c: \~licroStation VBA\exporttest.dgn
frmDFAV.frm Export
....
.. . .. .. .. .. .. .. .. . .. .. .. .. ....
. . .. .. . .. . . . . . . . . . ... . ... ... ........
. . . .. ...
.. ... . -..
.......... ..... .
. . . .. ... .... . .-,-
.. . . . .. . . . ... ..
r;; Include Sub-Folders . . . . ... ..
.. .. . . .. .,. ..
. .... ...
. .. . .... . . .. .. ..
. . .- . .. .. . . . .. . .
. Oesign F~es in Folder· 0 Files Found.
.. . .. . .... -. . . . .. ' ,
. .
......
. .. . . . . . .. . . . . . .. . . . ...... . . . . . .. . . . . . . ....
Control Names
[B txtFolder
[B btnBrowse
[B lstFiles
[B lstAttachments
We are going to add a few
elements in this program we
Select Root Folder:
have not used thus far. We
!±I.. My Documents
could have the user type in a $ .S iifill "I.IIIM
folder. Let's have them select it . $ ..... local Disk (C:)
ffie Key largo (D:)
instead. Here's the Folder !±I" ~ projects on 'Puny' (V: )
8:J"'~ Puny2Rem on 'Puny2' (Y:)
Selection dialog box we want: 8:J..:!! Store on 'Dev' (Z:)
$ 10 Shared Documents
How do we get it? We use the !±I IQ Administrator's Documents
8:J .. !ClJ Guest's Documents
Windows API. 8:J . 1O jerryw's Documents
, 8:J.jQ jkw's Documents
I+L~ M\I l\I,:Ih~lnrl.. PI~rp<:
The other thing we want to do
is store the settings of our Cancel
~ly Computer\HKEY _CURRENT _USER\Software\VB and VBA Program Settings\VBA File Attachment Viewer\Defaults
Program Components
[B Retrieve Settings from Registry on Form Initialize
[B Allow User to Select Root Folder
[B Search in Folder for .dgn files
[B Search in Folder's Sub Folders for .dgn files
[B When user clicks on file, display Attachments
I Provid ing User Feedback and Information I 383
Sub PopulateFileList ()
lstFiles . Clear
Dim myFolder As Folder
Dim myFSO As New FileSystemObject
If txt Folder.Text <> "" Then
Set myFo l der = myFSO .G etFolder(txtFolder.Text )
FilesInFolder myFolder , "dgn ", chkSubFolders , lstFiles
En d If
lblFiles . Caption = "Design Files in Folder - " &
lstFiles.ListCount & " Files Found. "
End Sub
I Providing User Feedback and Information I 385
available References: OK
Displaying Attachments
When the user selects a file in the Files listbox we get the attachments of
the selected file and display them in the Attachments ListBox.
the file because we do not want to open the file in MicroStation's editing
window each time a file is selected.
After the user has reviewed the attachments of the desired files, the user
closes the program. When a program is being closed, we want to store
the settings so the next time the program is executed we begin with
those settings in place.
Sub Macro5 ()
Dim startPo i nt As Po i nt3d
Dim point As Point3d , point2 As Point3d
Dim lngTemp As Long
388 I Chapter 17: Inte ractive Mod ification I
Dim modalHan dl er As New Macr o5M oda l Handl e r
AddModa l Dia l ogE ven t sHa ndler modal Handler
The following statement opens modal dialog "Select Image File "
Start a command
CadInputOueue.SendCommand "MOL LOAD PLAIMAGE"
End Sub
I Interacting with MDL Applications I 389
CadInputOueue.SerdCo~nand _
"MOL COMMAND MGDSHOOK.fileList_set~ilterCmd *.cal"
CadInputOueue.SendCommand _
"MO L COMMAND MGDSHOOK.fileList_setDirectoryCmd " &
"C:\Program Files\Bentley\MicroStation\"
CadInputOueue . SendCommand _
"MOL COMMAND MGDSHOOK.fileList_setFileNameCmd " &
"bentleyb . jpg "
Remove the following l ine to let the user close the di alog box .
Di alogResu l t = msdDialogBoxResultOK
End Sub
Every time the macro Macro5 is run, the same image will be placed in the
same place. Let's make a few modifications to the code we have so we
can create a more flexible and powerful class module that can be used in
future projects.
Here is the code for the new class module. It is named
clslmagelnsertion. We have added two public variables that act as
properties to this class module.
Implements IModalDialogEvents
Pub l ic FilePath As String
Publ i c FileName As String
Sub Te s t lm ag e ln se rtion ()
Dim po i nt 1 As Point3d, point2 As Po i nt3d
Di m mo dal Ha nd ler As New cl s lma ge l nse r t i on
modalHand l er . FilePath = "C: \ Pr ogram Fi le s \Be nt l ey\ Mi croS t at i on\ "
modalHand l er . Fi l eName = "bent l eyb. j pg"
Add Mo dalDi alogEve nt s Han dle r modalHa nd ler
Ca dlnp utOu eue . Se ndCo mmand "MO L LO AD PLAIM AG E"
point 1.X = 0: poin t 1 . Y = 0: poin t 1.Z = 0
poi nt2 . X = 1: poi nt2 .Y = 1: point 2. Z = 0
CadlnputOueue.S endDragP oints poi nt1, poi nt 2, 1
Remo ve ModalDial ogEvents Han dler mo dal Han dl e r
Co mmandState.Start DefaultCommand
End Sub
Using FilePath and FileName properties for the class module allows the
class module to be used with any file path or name. Previously, the path
and name were hard-coded.
REVIEW
The MicroStation VBA API is powerful. This power allows us to be
creative in how we approach programming tasks. For example, initiating
the "PLACE LINE" command to provide the user with a more
graphically rich experience when selecting two points can be used even
when we are not concerned with drawing a line. Using a modeless form
allows the user complete flexibility in working with the MicroStation
interface while allowing interaction with our own GUI.
18 Interface Essentials
In this chapter:
[B Interface basics
391
392 I Chapter 18: Interface Essentials I
[B The LocateCriteria object
[B IPrimitiveCommandEvents interface
[B Optimizing the dynamics event
INTERFACE BASICS
The ability to capture user interaction in MicroStation is powerful. To
harness this power, we create a new class module that implements the
interface. For example, to capture point selections in MicroStation, we
insert a new class module in our VBA project and place the following
line in the General Declarations area of the class module:
Implements
Implements IPrimitiveCommandEvents
End Sub
End Sub
End Sub
End Sub
End Sub
End Sub
Now we are ready to enter the code into the events.
SubP i ng()
MsgBox "Pinging " & IPAddress . Setl & &
IPAddress . Set2 & &
IPAddress . Set3 & &
IPAddress.Set4 , , Name
End Sub
Sub TestClsNetNodeA ()
Di m my Ne t Node As cl sNetNode
Set myN etN ode = Ne w clsNet Node
myN e tNode . Se tI PAddress 192. 168 , 1. 1
my NetNod e . Name = "Ro uter "
my Ne t Node.P i ng
End Sub
The second way to utilize a class module is to declare a variable as a
"New" class type and then begin setting variables and using methods as
shown below:
Sub Te s tClsNetNodeB ()
Di m myNetNode As New clsNetNode
myNetNode . SetIPAddress 192 , 168 , 1. 1
myNe t Node . Na me = "Router "
my NetN od e . Pi ng
End Sub
The difference between these two ways to declare and
initialize class modules is small. The net result is the
Pinging 192. 163. 1.1
same however in this example.
ILocateCorn rnandEvents
The ILocateCommandEvents Interface allows us to have the user select
or (Locate' an element. Here are the events exposed through the
ILocateCommandEvents interface:
[EJ Private Sub ILocateCommandEvents_Accept(ByVal Element As
Element, Point As Point3d, ByVal View As View)
[EJ Private Sub ILocateCommandEvents_CleanupO
I Class Module Lifecycle I 397
Implemen ts I LocateCommandEvents
Private SelEle ment As Element
End Sub
End Sub
398 I Chapter 18: Interface Essentials I
Privat e Sub ILo cateC omman dEv ents _ Loca teF i lt er( ByVa l _
Ele ment As El ement. Po in t As Po int 3d . Acce pted As Boolean)
Accepte d = False
If Ele ment .I sTex t Ele ment = True Then
Set SelElement = Eleme nt
Accepted = True
ActiveModelReference . Se l ect El ement El ement . Tr ue
ShowCommand "CAP Text "
ShowPrompt "Cli ck again to conf i rm. . . "
End If
End Sub
End Sub
LocateFilter Event
The first event we work with is the LocateFilter event. This event gives
us the ability to specify whether the element selected meets our criteria.
By default, the accepted property is true. If the accepted property
remains true, the user is given the opportunity to ''Accept'' the selection
by clicking again in MicroStation. When the user ''Accepts'' the
selection, the accept event is triggered and lhe code inside it is executed.
If in the LocateFilter event, the accepted parameter is set to false, the
LocateFailed event is triggered. It is common to re-start the interface
object if the LocateFilter event returns a false accepted value.
I Class Module Lifecycle I 399
Accept Event
Two conditions must exist before the accept event is triggered. First, the
LocateFilter event must exit with an accepted property of true. Second,
the user must "Accept" the already filtered element by left-clicking in
MicroStation. A right-click in MicroStation, after LocateFilter
successfully exits, resets the LocateFilter event but will not exit the
interface completely. When these two conditions (LocateFilter and User
Acceptance) are met, the code in the Accept event is executed.
LocateReset Event
The LocateReset event, the last triggered event in this interface, is
triggered when the user issues a reset by right-clicking in MicroStation
before the LocateFilter Event has been entered or after the LocateFilter
event has been entered but the accepted property has been set to false.
Remember that the LocateReset event is telling us that the user has
requested a reset. It is up to our code to exit the interface by issuing a
"CommandState.StartDefaultCommand".
LocateFailed Event
The LocateFailed event is triggered when the user clicks to select
something but nothing is located. This event could be used to exit out of
the interface by using "CommandState.StartDefaultCommand".
Start Event
The Start event, the first event triggered when utilizing this interface,
can be used to set up variables or other objects.
Cleanup Event
The Cleanup event is triggered just prior to the LocateReset event. As
the name implies, it can be used to clean up variables, objects, or
references used by the interface.
Dynamics Event
The Dynamics event provides dynamic real-time feedback. An example
later in this chapter demonstrates how it is used.
400 I Chapter 18: Interface Essentials I
Class Modules do not work by themselves - they need to be created by
other code. Here is the procedure that makes use of our new LeE_Text
class.
Tong e nt
Here are the I
CAP Text >Select Text to be Capitalized
screen shots of
the program
working. Notice
the command
and prompts
guiding the user.
I
CAP Text > Click again to conlirm ...
TANGENT
Element Selection> Identify efement to add to set
End Sub
I Class Module Lifecycle I 401
end Sub
End Sub
Private Sub ILo cate Comman dEvent s_ Loca t eFilter ( ByVal Ele ment As
Elemen t . Point As Point3d . Accepted As Boo l ean)
Acc ept ed = False
Dim elemText As TextElem ent
If Element . IsTextElement = True Then
Set elemText = Element
elemText . Redraw msdDrawingModeEra s e
el emTe xt.T ex t = UCase (el emTe xt .Te xt)
elemText.Redraw msdDraw ingModeNormal
elemText . Rewrite
ActiveModelReference.UnselectAllElements
CommandState.StartDefaultCommand
End If
End Sub
End Sub
Here is the code that initializes the Interface Object.
402 I Chapter 18: Interface Essentials I
Sub tstLCE_Text2()
CommandState . StartLocate New LCE_Iext2
ShowCommand "CAP Text"
ShowPrompt "Select Text to be Capitalized"
End Sub
We have not used the Dynamics event mentioned previously. Let's use it
now.
This code dynamically draws a new text element displaying the distance
between the original selection point and the cursor location. This is
done real-time. As the cursor moves, the text changes.
':S!
L oca ti on
+
A •
Here is the code for the Class Module named LeE DistanceText.
Implements ILocateCommandEvents
End Sub
LocateCriteria
When an element is 'located', we enter the LocateFilter method. In
previous examples we used this method to determine the type of the
selected element. This works but if we know the kind of element we
want, we can specify this before the selection is made by using
LocateCriteria.
End Sub
End Sub
End Sub
[B Sub ExcludeAllLevelsO
406 I Chapter 18: Interface Essentials I
[B Sub ExcludeAllTypesO
[B Sub ExcludeClass(ElemClass As MsdElementClass)
[B Sub ExcludeLevel(Level As Level)
[B Sub IncludeOnlyHoleO
[B Sub IncludeOnlyLockedO
[B Sub IncludeOnlyModifiedO
[B Sub IncludeOnlyNewO
[B Sub IncludeOnlyNonPlanarO
[B Sub IncludeOnlyNonSnappableO
[B Sub IncludeOnlyOldO
[B Sub IncludeOnlyPlanarO
[B Sub IncludeOnlySnappableO
[B Sub IncludeOnlySolidO
[B Sub IncludeOnlyUnlockedO
[B Sub IncludeOnlyUnmodifie dO
[B Sub IncludeType(Type As MsdElementType)
The MicroStation VBA help file explains the use of each method shown
here as well as examples of how they are used.
IPrimitiveCommandEvents
We just finished discussing the ILocateCommandEvents interface. Its
primary use is selection (or location) of elements in a design file. Use the
IPrimitiveCommandEvents object to capture command entry and point
selection.
Here are the events we have to work with:
[B Private Sub IPrimitiveCommandEvents_ CleanupO
I Class Module Lifecycle I 407
PCE_LineTest
The PCE_LineTest class draws a rubber-band line from the first point
selected to the current cursor location. After the second point is
selected, we use StartDefaultCommand to exit out of the class:
End Sub
End Sub
End Sub
End Sub
Most of the code in this example is in the DataPoint event and the
Dynamics event. Remember, we only want two points to be selected. We
use the variable boolSet so we know if the first point has been selected.
If the base point has not been selected, boolSet equals false and we take
the Point parameter and place it in the pt3BasePoint variable,
StartDynamics, and change boolSet to true.
As the cursor moves in MicroStation the
Dynamics event is triggered. This
happens many times per second. We
need to make sure the code in the
Dynamics event is not too time-
consuming. In this example, we create a
new LineElement between the initial point selected and the current
cursor location given to us in the Point parameter.
Interface objects cannot run by themselves. They need code in a code
module or a form to call them up.
Sub PlaceLine()
CommandState.S t ar tPr i mitive New PCE_ Line Tes t
End Su b
I Class Module Lifecycle I 409
Running this code demonstrates the fact that it works. The first point is
selected and the line is drawn as the cursor moves in MicroStation. After
the second point is selected, we exit the object. Normally we would not
leave this object as it is. We would do something with the two points. We
may draw a line between the two points. Or we could write code to
divide the selected points into four equal segments and draw circles at
those division points. We will see this in a future example.
The next example utilizes the same two point selection we saw in the
previous example. However, in this example we draw a rectangle using
the two points as bounding points. The only code that differs is the code
that generates a shape using the X and Y elements of the points to create
a rectangle. The name of this class module is peE_RecTest.
Implements IPrimitiveCommandEvents
Dim pt3BasePoint As Po i nt3d
Dim boolSet As Boolean
End Sub
End Sub
End Sub
End Sub
Notice how the X and Y elements of each shape vertex is derived from
the base point and the current cursor point.
Su b Pl ace Rec()
Co mmand State . Start Pri mit i ve Ne w PC E_Rec Test
End Sub
The procedure PlaceRec initiates the
PCE_RecTest class module.
After the first point is selected, a
rectangle is dragged from the first
point to the cursor. Since we are not
doing anything with the Reset event,
the only way to get out of this interface is to select the second point.
The CircleTest class draws a circle with a center at the first selected point
to the cursor.
Implements IPrimitiveCommandEvents
Dim pt3BasePo i nt As Point3d
Dim boolSet As Boolean
I Class Module Lifecycle I 411
End Sub
End Sub
End Sub
This example makes use of the Reset event. If the user resets the
command, we exit the interface object by calling StartDefaul tCommand .
412 I Chapter 18: Interface Essentials I
Sub Pl aceC i rc ()
CommandState.StartPrimit i ve New PCE_CircTest
End Sub
PCE_PolyTest
The PolyTest example draws a regular polygon circumscribed within an
imaginary circle centered at the first point and extending out to the
cursor location. We could draw a square, a triangle, or a hexagon. Which
should we draw? The PolyTest class can draw any regular polygon
because we specify the number of vertices. The code in the class module
is clear enough. The way we call up the class module differs from the
other examples we have looked at. Let's begin with the class module:
End Sub
Priv at e Sub IPr imiti veComma ndEve nt s_Dy nami cs( Po in t As Poi nt3d, _
ByVal View As View , ByVal Dr aw Mod e As Msd Dra wing Mode )
Dim pt3Po l yPo i nts() As Poin t 3d
ReDim pt3PolyPo'nts(O To Vertices - 1) As Point3d
Dim myShapeElem As ShapeElement
Dim I As Long
Di m db l BaseA ngle As Doub l e
db lB as eAngle = Atn((Po i nt . Y - pt3B asePoin t. Y) /
( Poi nt . X - pt3Bas ePoint . X))
For I = 0 To Ver t i c i es - 1
pt3PolyPoi nts(I) = Point3dAddA ngleOistance(pt3BasePoint , _
db lBa seAng l e + Radians(360 / Vertic i es * I) , _
Poi nt3dO i s t ance(pt3Base Poi nt , Point), 0)
Next I
Set myShapeE l em = CreateShapeElementl(Nothi ng , pt3PolyPoin t s )
myShapeE l em . Redraw DrawMode
End Sub
End Sub
End Sub
Take note that the vertices variable is declared as a public variable in the
General Declarations area of the class module. This allows it to act as a
property of the class module.
Sub Pl acePoly ()
Dim myPolyTest As New PCE_PolyTest
myPo l yTest . Vert i cies = 8
Comma ndState . St art Pri mi ti ve myPoly Test
End Sub
As we mentioned previously, we make use of the PCE_PolyTest class a
little differently than we did to the previous classes. In this example we
declare a variable as a New PCE_PolyTest. We need to do this so we can
414 I Chapter 18: Interface Essentials I
PCE_PointStringTest
Each PrimitiveCommandEvent interface example we have used up to
this point has been based on the user's selection of two points. We drew
a line between two points. We drew a rectangle using the two points as
opposing corners. We drew a circle using two points. We drew a polygon
using the two points.
The PCE_PointStringTest class allows for selection of more than one
point. In fact, there is nothing that prohibits the user from selecting an
endless number of points.
Implements IPrimitiveCommandEvents
Dim pt3BaseP oint As Point3d
Dim pt3Points() As Point3d
Dim boolSet As Boolean
End Sub
].
Multiple points are selected. As the points are selected, we are creating a
Point String element but we do not add it to the model. We only create it
and display it. If at any time the user resets the command, we exit out of
the class and the PointString disappears. When the user enters "plclose"
in the Key-in dialog box and hits <Enter>, we use the vertices that were
selected to create a Point String element and add it to the model.
So, we have seen the class module code and we have seen the results of
the class' work. How do we call it? Differently than any other in this
chapter.
Sub PlacePointString ()
CommandState . StartPrimitive New PCE_PointSt ri ngTest. True
End Sub
How is this different? We specify that we want to capture key-ins by
providing a value of true for the optional parameter "WantKeyins". The
default value of this parameter is false. So, when we want to capture key-
ins, we must specify a value of true when we use the StartPrimitive
method.
PCE_lineTest2
We want to allow the user to select two points. We will then divide the
space between the two points into equal length segments and draw
418 I Cha pter 18: Interface Esse ntials I
circles at each vertex of these lengths. Let's begin with the desired
interface and then we will discuss the code.
o o
o o
After the second point is selected, we draw circles dividing the area
between the selected points equally. In this example we specified
dividing the space into four equal segments.
Here is the code for the class module:
En d Sub
Di m I As Long
ReDim Di vPo i nts(O To lngDivisions - 2) As Point3d
pt3EndPoint Point
cblLineAngle = Atn«pt3EndPoint.Y - pt3Base Doint.Y) /
(pt3EndPoint.X - pt3BasePoint . X))
dblSegDist = Point3dDistanceXY(pt3BasePoint. pt3ErdPoint) /
lngDivisions
For I = LBound ( DivPoints ) To UBound(DivPoints)
DivPoints(1) =
Point3dAddAngleDistance(pt3BasePoint. _
dblLineAng l e . dblSegDist * (I + 1) . 0)
Next I
DrawCircle pt3BasePoint. 0 . 25
For I = LBound(DivPoints) To UBound(DivPoints)
DrawCircle DivPoints(1). 0.25
Next I
DrawCircle pt3EndPoint. 0 . 25
CommandState.StartDefaultCommand
End If
End Sub
End Sub
End Sub
A careful review of the above code reveals a method named
"DrawCircle': We use this each time we want to draw a circle. This keeps
the DataPoint event a little cleaner by breaking out a specific and
distinct piece of code into its own procedure.
Here are two examples that can be used to work with the PCE_LineTest2
class:
Sub PlaceLine2A()
Dim myLineTest2 As New PCE_LineTest2
myL i neTe st2 .1ngDivi sions = 4
Command State.S tartPrimitive myLineTest2
End Sub
Sub PlaceLine2B ()
Dim myLineTest2 As New PCE_LineTest2
myLineTest2.1ngDivisions = 12
CommandState.StartPrimitive myLineTest2
End Sub
The procedure Pl aceL i ne2A divides the selected points into four equal
segments. Pl ace Li ne2B divides the selected points into 12 equal
segments.
PCE_TestLine3
Our goal up to this point is to learn how to use the
IPrimitiveCommandEvents Object. We displayed lines, circles, and
polygons as we asked the user to select points. In the most recent
example we divided selected points into a specified number of segments
and placed circles at the segment points. We are going to expand on the
PCE_TestLine2 class in the next example.
PCE_TestLine2 is useful if we want circles drawn at a specific radius at
segment points. If we want to draw squares, we could create a new class,
copy and paste the code from PCE_TestLine2, then modify the new class
to draw squares. We would do the same to draw hexagons. We would
create a new class, copy and paste, then modify the code. To draw
octagons, we would create a new class, copy and paste, then modify the
I Class Module Lifecycle I 421
Sub PlaceLine3A ()
Dim myDivPo i nts() As Point3d
Di m myLi neTest3 As New PCE_ LineTest3
Dim I As Long
myLine Test3 . lngDivisions = 12
Co mmandState . StartPrimit ive myLineTest3
While myL i neTe st3 . ClassComplete = Fa l se
DoEvents
Wend
myD ivP oin ts = myLineTest3.DivPts
For I = LBound(myDivPoints ) To UBound(myDivPoints)
Dim my El l ip se As Elli pse Ele men t
Dim rotMatrix As Matr ix3 d
Set myEll i pse = Cr eateE lli pseEle ment2(Noth i ng. myDivPoints( I ) . _
0.25. 0.25, rotMatrix )
ActiveModelReference.AddElement myEllipse
Next
End Sub
Let's break this procedure down for discussion.
1 We declare Variables and initiate the PCE_LineTest3 class with the
use of the New keyword.
my LineTest3 . lngDivisions = 12
3 We start the PrimitiveCommandEvents object.
CommandState.StartPri mitive myLineTest3
422 I Chapter 18: Interface Essentials I
4 We look at the ClassComplete property of the PCE_LineTest3 class
and allow user interaction to continue while the value of the
ClassComplete property is false.
Next
End Sub
Follow through the code in Pl aceL i ne3B. What is it doing with the points
returned by the PCE_LineTest3 Class?
Sub PlaceLine3C ()
Dim myDivPoints() As Point3d
Dim myLineTest3 As New PCE_LineTest3
Dim I As Long
Dim Li neBasePt As Point3d
myLineTest3.lngDivisions = 16
CommandState .S tartPrimitive myLineTest3
While myLineTest3 . ClassComplete = Fal se
DoEvents
Wend
myDivPoints = my LineTest3.DivPts
LineBasePt.X = 3: LineBasePt.Y = 4 : LineBasePt. Z = 5
For I = LBound( myDivPoints) To UBound(myDivPoints)
Di m myLineElem As LineElement
Set myL i neE l em = Create Li neE l ement2(Noth i ng. LineBasePt . _
my Di vPoi nt s ( I ) )
ActiveModelReference.AddElement myLine Elem
Next
End Sub
What does this code do? Of course, we are using the PCE_LineTest3
class. But what are we doing with the returned points?
424 I Chapter 18: Interface Essentials I
We draw lines from each segment point to a single base point.
In each example where we used the PCE_LineTest3 class, we used a
Wh i 1e ... Wend structure to allow the user to select two points. After the
two points are selected, the value of "Class Complete" is no longer false
and we make use of the returned points. Each of the examples works
well without any modification to the class module. This is the most
desirable situation: a class module that can be used in a variety of
circumstances without any modifications.
Reviewing the code above shows that the class module has three
properties. One is named 'IngDivisions: another is named
'ClassComplete', and the last one is named 'DivPts'.
We have seen examples of how we will use PCE_LineTest3. Let's take a
look at the code behind the class module now.
End Sub
End Sub
End Sub
We have used most of this code before in our previous class
PCE_LineTest2, but let's focus on the DataPoint event. Previously, we
drew circles. Now we are placing the points into an array. Then we are
placing that array into a variable that had been publicly declared as a
variant. Declaring a variable as public in a class module allows it to be
used like a property of an object. In addition to placing the coordinates
into the DivPts variable, we set the ClassComplete variable to true. This
variable, Cla ssComplete, is read by the procedure that calls
426 I Chapter 18: Interface Essentials I
PCE_LineTest3 in the Whi 1e ... Wend structure. Even though we discussed
Pl aceL i ne3A previously, here is the procedure again:
Sub PlaceLine3A()
Dim myDivPoints() As Point3d
Dim myLineTest3 As New PCE_LineTest3
Di m I As Long
myLineTest3 . lngDiv i sions = 12
CommandState.StartPrimitive myLineTest3
Wh i le myLineTest3.ClassComplete = False
DoEv en ts
Wen d
myDiv Po i nt s = myLi neTes t 3 . Di vPts
For I = LBound(myDivPoints) To UBoun d( myDivP oints)
Dim myEllipse As Ellipse Elemen t
Dim rotMatrix As Matrix3d
Set myEllipse = CreateEllipseElement2(Nothing. myDivPoints(I) , _
0 . 25 , 0 . 25, rotMatrix)
ActiveModelReference . AddE le ment myEl li pse
Next
End Sub
Once we use StartPrimitive, we begin looking at the ClassComplete
property and wait until ClassComplete is set to true. When
ClassComplete is true, we can get the points from the DivPts property of
the class.
Di m my Li ne El em As Li ne El ement
Set myLineE l em ~ CreateL i ne Element2(Nothing , pt3BasePoint , POint)
my LineEle m. Redraw DrawMod e
End Sub
Each and every time this dynamics event is triggered, we do the
following:
1 Declare a variable as a LineElement.
2 Create a LineElement.
3 Redraw the LineElement.
Three lines of code are in the event - each line takes up processor time.
What we don't see in the code is that the LineElement goes out of scope
when we exit the dynamics event. This takes time because VBA has to
dump the memory that had been assigned to the object. Imagine setting
aside memory, drawing a line, and then dumping the memory over 390
times just because the cursor moves from the left to right.
Let's compare "PCE_LineTest" with a different implementation of the
Dynamics event in "PCE_LineTest4".
End Sub
End Sub
End Sub
End Sub
We declare the variable, create the line, redraw it, then terminate it
(because it goes out of scope) each time the dynamics event is triggered.
Now let's look at the difference between PCE_LineTest and
PCE_LineTest4.
End Sub
pt3BasePoint = Point
Set myLineElem = Create LineElement2(Nothing. Point. Point )
CommandState.StartDynamics
boolSet = True
E1 s e
CommandState . StartDefaultCommand
End If
En d Sub
End Sub
End Sub
End Sub
In PCE_LineTest4, we declare the variable for the LineElement in the
General Declarations area. We create the line once in the DataPoint
event. When we get to the Dynamics event, all we do is change the
EndPoint of the line and redraw it. This is a much more efficient way to
work with the Dynamics event.
PCE_LineTest and PCE_LineTest4 are simple and small. Although it
may not be apparent when using these two classes, PCE_LineTest4 uses
significantly less processor time. Minor changes like the one we made
for PCE_LineTest4 may not make an immediate dynamic difference in
the efficiency of our code, but little efficiencies add up to significant
performance benefits. The opposite is true as well. Inefficiencies add up
to significant performance degradation.
430 I Chapter 18: Interface Essentials I
REVIEW
We implement interfaces through class modules. Each property or
method of the interface that we implement must be declared in the class
module. When we implement the interfaces discussed in this chapter,
we can have greater control, flexibility, and power in our programming
as our applications become more interactive.
19 Using MicroStation's
Built-In User Forms
In this chapter:
[B Declaring MicroStation user form functions
[B The FileOpen dialog
[B The FileCreate dialog
[B The FileCreateFromSeed dialog
[B The OpenAlert dialog
[B The OpenlnfoBox dialog
431
432 I Chapter 19: Using MicroStation 's Built-In User Forms I
Declare Functio n mdlDialog_openAlert Lib _
"stdmdlbltin.dl l " ( ByVal s tringP As St r ing) As Lo ng
Here is the declaration for the OpenAlert dialog box. Let's break up the
declaration into its individual parts:
: ~~
~'
Ope!! File -- C:\Micro~~a!io!I.VB.A\':~~"">.:J»'.<"'~ '" " , '" , ," " ~ < • .. ·",t
~
~file9 . dgn
;
[
M~ Computer ;
;
~.
File name: ! h... ! Open il
~
W,~,
From this dialog we can see how m any of the Procedure Parameters are
used. We can see the Title, the Default Directory, the Filter (* .dgn) and
we can see that we did not supply a Default File Name because the File
Name is blank.
Up to this point, the only thing we have done is displayed a dialog box.
Now we must ask a few questions.
Did the user click the Open button or the Cancel button?
Select Case retVal
Case 0 ' Ope n
Case 1 ' Cancel
End Select
We look at the return value of the function to see if the Open button was
selected (resulting in a return value of 0) or if the Cancel button was
selected (returning a value of 1).
If the Cancel button was selected, there is little to do because the user
Cancelled the operation. In our example we display a MessageBox
stating "No File Selected".
If the user clicks the Open button, the next question is "Which file was
selected?"
I Declaring MicroStation User Form Functions I 435
strFName = Space(255)
The Spa c e function fills the variable with the number of spaces specified.
If we provide a space-buffered variable to the 0pen Fi 1e function, the
variable will be filled with the fully qualified path of the file selected.
Supplying a variable with 255 spaces in it returns a variable with 255
characters, even if the path and file name are only 20 characters in
length. Using the Left function, we get everything to the left of the first
Null Character (ASCII Character of 0).
MessageBox:
We can see that we are generating a File Open dialog box. The user
selects a file and clicks "Open" but the dialog box does not open the file.
lt only tells us which file was selected. It is up to us to open the selected
file or perform some other operation on it. In our first examples we will
only display the file name in a MessageBox.
Here is a slight variation on TestFi 1eOpenA . Only one change has been
made:
;
D
Recent
'j'!Q Fonts
!Q cd material
IC) Source Code
~filel0.dgn
~filea.dgn
!!Q pics ~fileb . dgn
@ ll~file1.dgn
!iCl docs ~ rasterdocs.dgn
Il
Desktop I ~file2.dgn
l ~file3.dgn
i ~file4.dgn
1 ~ ~file5,dgn
II ;',
i ~file6 . dgn
. My Documents
l~ file7.dgn
Ibij) fileS .dgn
I'
~
My Computer
. 1________________________________________
I ~I
------.-.-.--.------..-.---.----.-.---.-.---..-.--..'"':1
~
I
Filename: [.mmm! _ _ _ .v ;, Open
.. __Ivtl'._~!:~g!~ _I
o Open as l ead·only
'.1;, .. ~
default file name of test4.dgn. This test4 .dgn
File not found.
file does not exist in the folder please verify the correct file name was given.
Our previous example used a file extension, also called a file filter, of
"*.dgn". MicroStation understands that this file extension is a
"Micro Station DGN File" and shows this in the "Files of type" combo
box. TestFi 1eOpenC uses a file filter of "*.xls". This displays Microsoft
Excel files in the dialog box.
Sub TestFileOpenC ()
Dim strFName As String
Dim lngfhandle As Long
Dim ingrid As Long
Dim retVal As Long
strFName = Space(255)
retVal = mdlDialog_fileOpen(strFName. lngfhan dle. lngrid.
"*.xls ". "C:\MicroStation VBA ". "Open File")
Se l ect Case retVal
Case 0 ' Open
strFName = Left(strFName. InStr(l . strFName . Chr(O)) - 1)
MsgBox "File Selected :" & vbCr & strFName
Case 1 ' Cancel
MsgBox "No File Se l ected ."
' User hit the Cance l Button
End Select
End Sub
Now, instead of displaying MicroStation DGN files, Microsoft Excel
(XLS files) display.
438 I Chapter 19: Using Mi croStation's Bu ilt- In User Forms I
IClFonts
;Qed material
Recent QSouree Code
;Qpies
Fr~ o does
~ , ~MS VBA version 2.xls
Desktop ~Book2.xls
~ Enums,xls
r~'\ ~Microstation Object Model.xls
v:;:; : ~Learn'ng MS VBA.xls
Let's look at another example that displays more than one type of file.
Sub TestFileCreateA()
Dim strFName As String
Dim lngfhandle As Long
Dim lngr id As Long
Dim retVal As Long
strFName Space(255)
retVal mdlDialog_fileCreate(strFName , lngfhandle, lngrid, _
"", "*.dgn ", "C:\MicroStation VBA", "Create File A" )
Select Case retVal
Case 0 'Open
strFName = Left(strFName , InStr(l, strFName , Chr(O)) - 1)
MsgBox "Fi l e Selected : " & vbCr & strFName
Case 1 ' Cancel
MsgBox "No Fi l e Se l ected. "
' User hit the Cancel Button
End Select
End Sub
The FileCreate dialog has the same look and feel as the FileOpen dialog
box.
Sub Te stFileCreateFromSeedA ()
Dim strFName As String
Dim lngfhandle As Long
Dim lngrid As Long
Dim retVal As Long
Dim strSeedFile As String
Dim strSeedDir As String
Dim strSeedFilter As String
strFName = Space(255)
strSeedFile = "seed2d.dgn"
442 I Chapter 19: Using MicroStation's Built-In User Form s I
strSeedOir =
"C: \Oocuments and Sett i ngs \A ll Us er s\Ap pl i c ation " &
"Oata \ O oc ~men t s\Bentiey \ Workspace\Syste m \Seed \ "
EJ Ii ei~~~f~]
, ~filea.dgn
; ICl cd material ~fileb.dgn
i
Recent rQ Source Code ~rasterdocs.dgn
i D pics
:
[»
I rQ docs
I ~filel.dgn
Desktop i ~ file2. dgn
! ~file3.dgn
I ~ file4 . dgn
v!J
My Documents
! ~ fileS.dgn
~ file6.dgn
I ~ file7 . dgn
t ~ file8 .dgn
~file9. dgn
~ filelO . dgn
My Computer
i
f&l I
!
Filename: I1--- ----- - ---· --·-- - - -,vi] i Save l
... ~y. N ~twor~ ,. : Save as ll'pe: . MicroS tation DGN Files (". d g n j v_ ( Cancel
I
Seed: 1~:'D?::uments a~d.. Set~in~~~II. Users~pliGat~0!l [ Browse I
."
I Declaring MicroStation User Form Functions I 443
Sub TestOpenAlertA()
Dim re tVal As Long
retVal = mdlDialog_openAlert( "Standard Message Box")
Select Case retVal
Case 3 'OK
MsgBox "User cl icked 'OK '"
Case 4 ' Cance l
MsgBox "User c l icked ' Cancel '"
End Se lec t
End Sub
Sub TestOpenlnfoBox ()
Dim retVal As Long
444 I Chapter 19: Usin g MicroStation's Bui lt-In User Forms I
retVal = mdlDialog_openlnfoBox( "This is a test. " )
Sel ec t Case retVal
Case 3 'OK
MsgBox "User cl i cked 'OK '"
End Select
End Sub
- . _. ~ ~ ~~ <',~~ '"/1 '" '70< ., ~ • ~,
I"formation ,
This is a test.
REVIEW
After declaring the functions that display standard MicroStation dialog
boxes, using them is simple. There are other ways to display File Open,
File Create-type dialog boxes (such as using the Windows API) but
using the standard MicroStation dialog boxes is the preferred method
when developing in VBA and is so easy to implement.
20 Class Modules
In this chapter:
IB Encapsulating similar functionality
IB Creating objects with properties, methods, and events
IB Using class modules with collections
445
446 I Chapter 20: Class Modules I
The first element in the array is always an empty string. As you add file
extensions, remove the period character and add it as lowercase.
When you call the C1ear Fi 1eExt s method, remove all elements except
the first element by redeclaring the variable pFileExts with an upper-
bound index of zero (0).
You are able to add file extensions to our class module now. You can also
clear the list. Give yourself the ability to discover what and how many
file extensions have been added by adding two properties to the class
module. The first property is "ExtCount" which tells how many file
extensions have been added to the class; the other is "GetExts" which
returns an array of all file extensions added to the class.
In the past, we created properties for our class modules by declaring a
variable as public. This works but there is a better way to work with
properties.
I Encapsu lating Simi lar Functionality I 449
The ExtCount property tells how many file extensions have been added
to our class. If you declare a variable named Ext Cou nt as public, you will
be able to read and write to the variable. This is not good because the
property's value should be based on the actual number of extensions
that have been added. You do not want to be able to write to the
property since it should be read -only.
Sub TestGetExts ()
Dim MyUSD As New cl sUStationD i alog
Dim Fi l eExts() As Stri ng
MyUS D. AddF il eExt ". dgn "
MyUSD . Add Fil eExt "DGN "
MyUSD . Add FileExt ". DWg "
MyUSD . AddFi l e Ext "Xl s "
Fi leExts = MyUSD.Ge t Exts
End Sub
Notice how we are attempting to add the .dgn file extension twice. If the
AddFileExt method is working properly, you see only one dgn
extension.
Here is a view of a
Watch added to the
variable "FileExts".
Three unique file extensions were added and they are properly retrieved
by the GetExts property.
It is now time to allow the user to set and get the default directory for the
File Open dialog box. Make this property read/write using "Property
Let" and "Property Get".
Declare a variable named pDefFilePath in the General Declarations area
of your class.
I Encapsulating Similar Functionality I 451
Sub TestFilePathA ()
Dim MyUSD As New clsUStationDialog
MyUSD . DefaultPath = "abc : \/?test "
End Sub
If we run the code, "abc: \/?test" is set as the default path in our class. The
code worked exactly as designed. It took the value supplied and plugged
it in. So, if the code worked, we are in good shape. Right? Wrong.
Is "abc: \/?test" a legitimate path? At the time of the printing of this book,
it is not. So, what are we to do?
When a property is read/write, we could get away with declaring a
variable as public in the class. This allows us to read from and write to
the variable, making it behave like a property. But the properties of our
objects (classes) must be more than variables we can read from and
write to. Before any property is truly implemented, consider whether
you need to validate the supplied data. In this example, we need to make
sure the path exists. There are several ways to do this. Here is one way.
452 I Chapter 20: Class Modules I
Modify your "Property Let DefaultPath" statement.
Now, even if we supply an illegitimate path, the program will not crash.
Let's implement the "DefaultFileName" Property.
End Property
Let's review what we have accomplished thus far. We have taken care of
the file extensions. We can set the default path. We can also set the
default file. This is all we need to do to begin work on displaying the
FileOpen dialog box.
We need to declare the function "mdlDialo~fileOpen" in the General
Declarations area of the class module as follows:
Private Declare Function mdlDialog_fileOpen Lib "std mdlbltin . dll " (ByVal _
fileName As String, ByVal rFileH As Long, ByVal _
resourceld As Long, ByVal suggestedFileName As String, _
ByVal filterString As Str i ng. ByVal defaultD i rect o ry As String. _
ByVal titleString As String) As Long
Private pF i leExts() As St r i ng
Sub Openoialog()
Dim t mpFilter As String
pRetVal = 1
tmp Filter = " *." & Join(GetExts, " *. " )
pFileNameSelected = Spac e (255)
pRetVal = mdloialog_fileOpen(pFileNameSelected, 0, 0, _
poefFileName, tmpFilter, poefFilePath, "Open File")
Select Case pRe tV a l
Case 1 ' Cancel
Case ° ' Open
Dim tmpFile As String
Dim xSp l it As Variant
tmpF i le = Left(pF i leNameSelected, InStr(l, _
pF i leNameSe l ected, Chr(O)) 1)
xSplit = Split(tmpFile, "\ " )
pFileName = xSpl i t(UBound(xSplit))
xSpl i t(UBound(xSplit)) =
pFilePath = Join(xSplit , "\ " )
End Select
End Sub
456 I Chapter 20: Class Modules I
Pr ope r ty Get Defau l t Fi le() As St ri ng
DefaultF i l e = pDefFileName
End Property
Pub li c Su b Cl earFileExts()
ReDim pFileExts(O)
End Sub
Sub TestShowDialogA()
Dim My USD As New clsUStationDialog
MyUSD.AddFileExt "dg n"
MyUSD.D ef au l t Path "c:\ "
MyUSD . DefaultF i l e = "test.dgn "
MyUSD . OpenD i alog
Se l ect Case MyUSD.OpenSuccess
Case True
MsgB ox My USD.SelectedPath & My USD. Sele ct edFile
End Sel ect
End Sub
Let's try a variation on Tes tShowDi a1ogA just to make sure everything is
working properly.
Su b TestShowDialogB ()
Di m MyU SD As New cl sUSt ati on Dial og
MyUS D.Ad dFil e Ext "dgn "
458 I Chapter 20: Class Modules I
MyUSD.AddFileExt "dwg "
MyUSD .A ddFile Ext "dx f "
MyUSD.DefaultPath " c:\MicroStatio~ V8A "
MyUSD.DefaultFile = "test.dgn"
MyUSD.OpenDialog
Select Case MyUSD.OpenSuccess
Case True
Msg80x MyUSD.SelectedPath & MyUSD.Sele ctedF ile
End Select
End Sub
Each file extension added to the class displays in the FileOpen dialog
box.
Sub CreateDialog()
Dim tmpFilter As String
pRetVal = 1
tmpFilter = "*." & Join(GetExts . " *.")
pFi l eNameSelec t ed = Space(2 55 )
pRet Val = mdlDialog_f i leCreate(pF i leNameSelected, 0 , 0, _
pDefF i le Name , tmpF i lter . pDefFi l ePath. "Cr eate File " )
Select Case pRetVal
Case 1 . Cancel
Case 0 ' Open
Dim tmpFile As String
Dim xSplit As Variant
tmpFile = Left ( pFileNameSelected, InStr(l,
pFileNameSelected, Chr( O)) 1)
xSplit = Split(tmpFile. "\ " )
pFi 1 eName = xSp l it (UBound (xSpl it) )
xSplit(UBound(xSplit)) =
pFilePath = Join(xSplit. "\ " )
End Select
End Sub
It is now time to test the CreateDialog method of our class.
Sub TestShowDialogC ()
Dim MyUSD As New clsUStationDialog
MyUS D.AddFileExt "dgn "
MyUSD.Defau l tPa t h = "c : \ "
MyUSD . Defau lt Fi 1 e = "test. dgn "
MyUSD . CreateDialog
Select Case MyUSD . OpenSuccess
Case True
MsgBox MyUSD . SelectedPath & MyUSD.SelectedFile
End Select
End Sub
460 I Chapter 20: Class Modules I
TestSh owDialogC is almost an identical copy of TestShowDialogA. The
only difference is we are using CreateDialog instead of OpenDialog.
Everything else is the same.
Copy and paste TestShowDialogB to create TestShow Dialog D and make
the same change.
End Select
End Sub
What are we doing in TestSh ow DialogE? We prompt the user to select a
file to open. If the user selects an existing file, we display the file name in
a MessageBox. If the user clicks the Cancel button, the
MyUSD.OpenSuccess property will be False, so we to ask if the user
wants to create a new file. If the user answers No, do nothing. If the user
answers Yes, display the FileCreate dialog box and allow the user to
create a new file. If the user successfully creates a file using the
FileCreate dialog box, display the file path and name in a MessageBox.
Notice how easy it is to add Fi 1eCreate functionality to the class module
and to use the Crea teDi alog method in the procedure. When you outline
functionality to include in class modules, you can expand them quickly
and easily.
From this point on, any time you need to use the FileOpen or FileCreate
dialog box, you can use the class you just created. But how can you use it
in future projects? Do you need to copy and paste the code each time
you want to use it? There is a better way.
From the VBA Project Window (not to be confused with the VBA
Project Manager), right-click on the class and select Export File.
i [lsert
&emove ellsUStal:i6nDialoo.
~rint" .
. Doc!>;ble
tJide
462 I Chapter 20: Class Modules I
Select a location and save the file.
create a new clsLineElem Class and include a few properties that are not
a part of the MicroStation Object Model.
To simplify matters, we will have our Start and End Point properties
implemented by declaring two variables as public within the General
Declarations area of the class module.
To make sure things are working correctly, create a test procedure to
work with the class.
Create a MidPoint property next.
Sub TestNewLineA ()
Dim myLE As New clsL i neElem
End Sub
When you run this macro, you will see the following MessageBox:
Compile error;
Constants, fixed-length strings, arrays, user-defined types and Declare statements not allowed as Public members of object modules
OK II Help
10 Double
y 10 Double
Z 10 Double
Point3d
Double
Double
Z Double
Point3d
Point3d
Double
Double
Double
End Property
Enough with properties. Let's look at creating methods. The first one
will be DrawLine.
Sub OrawLinePerp ()
Dim PerpSt As Point3d
Dim PerpEn As Point3d
Dim PerpMid As Point3d
I Creating Objects with Properties, Methods, and Events I 467
Sub TestNewLineE ()
Dim myLE As New clsLineElem
myLE.StartPoint = Point3dFromXYZ(O. O. 0)
myLE .E ndPoint = Point3dFromXYZ(8. 8. 0)
myLE .Draw Line
myLE.DrawLinePerp
End Sub
Two lines are drawn. One from (0, 0, 0) to (8, 8, 0) and another
perpendicular to the first one through the mid-point of the first one.
Add another method to the class module. First the code, then the
explanation:
Sub DrawCircle ()
Dim CircE l em As EllipseElement
Di m Ro tM atrix As Matr i x3d
Set Ci rcElem = CreateE ll ipseElement2(Noth i ng. MidPoint. _
Po i nt3dDistance(pStartPo i nt . pEndPoint) / 2. _
Po i nt3dD i stance(pStar t Po i nt . pEnd Point) / 2 . RotMatrix)
Act i veMode l Reference . Add Element Ci rcElem
End Sub
DrawC ire 1e draws a circle through the end points of the LineElem object.
468 I Chapter 20: Class Modules I
One of the great things about the class module is that we can add
methods and properties whenever we see a need. At this point, the three
methods in our class module may be all we need in the application right
now. Later, if the next application needs a m ethod named
"DrawLineSegments" to specify the number of line segments between
the start point and end point, we can add it. We can add any number of
methods and properties to our class module but we need to be careful.
Be even more cautious when mo difying existing methods and
properties.
For instance, we have a property named StartPoint declared as a Point2d
type that works in many circumstances. Changing it to a Point3d type
might seem as though it would support more methods and properties.
But changing a variable from a Point2d to a Point3d may cause code
already using the Class Module to fail because functions or procedures
in the existing code expect a Point2d type. Careful planning helps avoid
making changes to class module properties and methods after they are
in use.
We covered properties and methods, but what is an event? An event is
triggered when a specific activity takes place. We usually write code in
events to react to user interaction.
Let's create an event in our class to be triggered whenever a line is
created and drawn in MicroStation.
In the General Declarations area of the class, the following code creates
an event:
Su b Dra wL ine()
Dim Li ne Elem As LineElement
Set Line El em = Cr ea t eL i ne El ement2( Noth i ng ,
pS ta r t Poi nt , pEndPoint)
ActiveModelReference . AddElement LineElem
RaiseEvent LineAdded( LineElem)
End Sub
I Creating Objects with Properties, Methods, and Events I 469
When you declare a variable this way, the variable's events are available
like the events of a CommandButton.
The object myLE (it uses the variable name, not the class name) is now
available in the Object ComboBox of the form's code.
cl s Lin e El em
v
> ..
470 I Chapte r 20: Class Mod ul es I
After selecting myLE in the Obj ect ComboBox, you can see the
clsLineElem Events in the Procedure ComboBox.
Sub TestCollectionA ()
Dim myColl As Ne w Co llect ion
Di m my Level As Leve l
For Each my Level In ActiveMode l Reference . Levels
myColl .Add myLeve l
Next
End Sub
I Using Class Modu les with Collections I 471
Long
String
msdLevelElementAcce ssAIl MsdLevelElementAccess t
0 Long
Linest yleilineStyle
0 Long
Long
IsActive True Boolean
IsDisplayed True Boolean
IsFr omLe velLibrary False Boolean
IsFrozen False Boolean
IslnUse False Boolean
IsLa eked False Boolean
Name "Level·l " String
Number 1 Long
OverrideColor 0 Long
OverrideLinestyle LinestylelLineStyle
OverrideLineWeight 0 Long
Parent Level Nothing Level
Plot True Boolean
UsingOverrideColor True Boolean
USingOverrideLinestyle True Boolean
UsingOverrideLineWeight True Boolean
~ em 2 Variant lObjectilevel
~em 3 V ariantlObjectilevel Iv
Each added object shows up as an item in the collection. You can see the
type of object in the Type column. All of the object's properties display
with their values.
Sub TestCollectionC ()
Di m myCo ll As Ne w Coll ec t io n
Dim myLev el As Level
For Ea ch myLevel I n ActiveMo de l Reference . Leve l s
myCol l .Add myLevel
Next
' Now t hat t he collection is populated ,
' acce s s t he objects us in g t he i tem I ndex .
Dim myL eve1 2 As Lev el
Di m I As Long
For I = 1 To my C01 1 . Count
Set my Leve l 2 = my Co l 1 ( I )
Debug. Pr i nt my Leve12 . Name
Next
End Sub
We are still cycling through each item in the collection but now we are
accessing each item by addressing it by the item's index in the collection.
Sub TestCollectionD ( )
I Using Cla ss Modules with Collections I 473
Sub TestCollectionF()
Dim myColl As New Collection
Di m my Level As Level
For Each myLevel In ActiveModelReference.Levels
myCol l .Add myLevel . myLevel.Name
Next
' Now that the collection is populated.
' address a Level by it's Key.
Dim myLeve12 As Level
Set my Leve12 = myCo ll ( "Default")
MsgBox myLeve12.Number
End Sub
474 I Chapter 20: Class Modules I
We know each MicroStation DGN file has a level named "Default".
Because we may not know what its index in the collection will be, access
the level in the collection through the object's key.
Keys must be unique strings. In other words, no two objects in a
collection can have the same key. Keys are not case-sensitive so you
cannot have a key of "test" and a key of "TEST" in the same collection.
Sub TestCollectionE()
Dim myCo ll As New Collection
Dim my Level As Level
For Each myLevel I n ActiveModelReference.Levels
myCo ll .Add myLevel
Next
'Now that the co l lect ion is populated,
'remove the objects using the item I ndex.
Di m I As Long
For I = my Co l 1 . Co unt To 1 St e p - 1
myCo ll .Remove I
Nex t
En d Sub
we draw a line between the entered X and Y values and the Start and
End Points of the myLineElem object.
Enter X Value: I OK · I
[ Cancel I
Enter Y Value:
OK I
I Cancel I
REVIEW
Classes can encapsulate similar functionality, create objects with unique
properties, methods, and events, and group similar objects for a variety
of purposes into collections. The more you implement classes in your
programs, the more you are following the ideals of object oriented
programming.
21 VBA for CAD Managers
VBA is not just for programmers and not just for MicroStation users -
it is a powerful tool for CAD Managers as well.
In this chapter:
[8 Using VBA for maintaining standards
[8 Protecting projects
479
480 I Chapter 21: VBA for CAD Managers I
NOTE: For more information on maintaining standards, look at the
Standards Checker Interface which provides powerful functionality
with built-in reporting capabilities.
The first thing to create is a procedure that looks for unsupported levels.
~~l
<::F I XI
I Using VBA for Maintaining Standards I 481
This works well for finding un-supported levels. What do you do if a file
is supposed to have levels but they aren't there? Look for missing levels
next.
Sub FindMissingLevels ()
Di m GoodLevels(O To 4) As Str i ng
Dim Le velFound(O To 4) As Boolean
Di m my Le ve 1 As Level
Dim I As Lon g
GoodLevels(O) "ROADWAY "
Goo dLev el s(l) "SIDEW ALK"
GoodLeve l s(2) "PA I NT"
GoodLevels(3) "ELE CT RI C"
GoodLevels(4) "GAS "
GoodLevelsJ = UCase("- " & Join(GoodLevels, "- " ) & "-")
For Each myLevel In ActiveDesignFi l e.Levels
For I = LBound(GoodLevels) To UBound(GoodLevels)
If StrComplGoodLevelslIl , myLevel .N ame, vbTextCompare l = 0 Then
Leve lFound(I) = True
End If
Next I
Next
For 1= LBoun d(GoodLeve ls) To UBound(GoodLevels )
If LevelFound(I) = False Then
Debug.Print "MISSING LEVEL: " & GoodLevels(I)
End If
Next I
End Sub
Above, the code is ready to report missing levels to the Immediate
Window.
When is the last time a CAD Manager turned in a report consisting of a
screen capture of the Immediate Window in VBA? Let's add some code
to copy and paste versions of the two above procedures to write to an
ASCII text file.
Sub FindUnsupportedLevelsB ()
Dim GoodLevels(O To 4) As String
Dim GoodLevelsJ As Str i ng
Dim my Level As Level
Dim FFile As Long
482 I Chapter 21 : VBA for CAD Managers I
GoodLevels(O) "ROADWAY"
GoodLevels(l) "SI DE WALK "
GoodLevels(2) "PAINT"
GoodLevels(3) "ELECTRIC"
GoodLevels(4) "GAS "
GoodLevelsJ = UC ase(" - " & Join(GoodLevels, "- ") & "- " )
FFile = FreeFile
Open "C; \M icroSta tion VBA\LevelsUnSupported.txt" For Output As # FFi le
For Each myLevel In ActiveDesignFile.Levels
If InStr(l , GoodLevelsJ. "- " & UCase( myLevel . Name) & "_H) = 0 Then
Print #FFile . ActiveDesignFile . Path & ActiveDesignFile .Na me & _
vbTab & "Unsupported Level Found: " & myLevel . Name
En d If
Next
Close #FFile
End Sub
Sub FindMissingLevelsB ()
Dim GoodLevels(O To 4) As String
Dim LevelFound(O To 4) As Boolean
Dim myLeve l As Level
Dim I As Long
Dim FFile As Long
GoodLevels(O) "ROADWAY "
GoodLevels(l) "SIDEWALK"
GoodLevels(2) "PAINT"
GoodLevels(3) "ELECTRIC "
GoodLeve l s(4) "GAS "
GoodLeve l sJ = UCase("-" & Join(GoodLevels. "-") & "- ")
FFile = FreeFile
Open "C;\MicroStation VBA\LevelsMissing.txt " For Output As #FFile
For Each myLevel In ActiveDesignFile .Le vels
For I = LBound(GoodLevels) To UBound(GoodLevels)
If StrComp(GoodLevel s( I ). myLevel. Name. vbTextCompare) = 0 Then
LevelFound(I) = True
End If
Next
Next
For I = LBound(GoodLevels) To UBound(GoodLeve l s)
If LevelFo und (I) = False Then
Print #FFile. ActiveDesignFile.Path & ActiveOesignFile.Name & _
vbTab & "MISSING LEVEL : " & GoodLevels ( I )
I Using VBA for Maintaining Standards I 483
End If
Next I
Close #FFile
End Sub
You are writing to an ASCII file. Place a tab between the filepath/name
to make the file tab-delimited. Why tab-delimited? Because it is easy to
import the file into Microsoft Excel and other programs capable of
reading tab-delimited ASCII files.
What's next? Consider the pain involved in opening hundreds of DGN
files and running this macro one-by- one. VBA is supposed to solve
these types of problems and make life easier and more pain -free.
Make a small change to your procedure to append the ASCII file when it
is opened. When you open a file for output, the existing file (if it exists)
is overwritten. When you open a file for append, the existing file (if it
exists) is appended to and created if the file did not previously exist.
Sub DoFileslnFolder ()
Dim MyFSO As New FileSystemObject
I Cross-Company Standards I 485
Di m myFolder As Fo l der
Di m my Fi 1e As Fi 1e
Set myF ol der = MyFSO . GetFolder( "C: \Documents and Settings \ " & _
"A'l Users\Application Da:a\Documents\Bentley\WorkSpace\" &
"Projects\Examples\Arcnitectural\Dgn")
For Each myFile In myFolder . Files
Select Case UCase(Right(myF i le.Name . 3))
Case "DGN "
Di m my DGNF ile As De sig nFile
Set myDGNFile = OpenDesignFileForProgram(myFile.Path)
Find Un s up portedLeve l sC my DGNFile
FindM i ss i ngLeve l sC myDGNFi l e
myDGNFile.Close
En d Sele ct
Next
End Sub
The procedure DoFi 1esIn Fol der takes a hard -coded file path and opens
each DGN file in the path "ForProgram': This means it is not opened in
the MicroStation editor window but we can manipulate the files using
VBA.
The example shown opens files added to our hard drives when
MicroStation is installed. In less than one second, seven files are opened,
levels are identified, and text files are written.
Use the examples shown here to spark your creativity. There are other
elements, in addition to levels, you could use to maintain standards.
Indeed, an entire book could cover examples of verifying a multitude of
criteria. Since this is not the focus of this book, I will leave additional
functionality to your imagination.
For more related information, see Chapter 30, "Batch Processing:'
CROSS-COMPANY STANDARDS
Two companies need to work with each other's files but one company
has a level named "STREET" while the other has one named "Level 20".
How can VBA help companies work with different standards?
The procedure Leve 1SpecA translates one standard to another for level
names. When the procedure finds "Level 20", it changes the name to
"STREET". The other level name mappings are easy to see.
486 I Chapter 21: VBA for CAD Managers I
name. They see what they are accustomed to seeing and are much more
productive as a result.
Before returning the file to the originating company, it would be polite
for us to set the Level names back to what they had been.
Sub LevelSpecB ()
Dim my Leve 1 As Level
Dim I As Long
For I = 1 To ActiveDesignFile.Levels.Count
Set my Leve 1 = ActiveDesignFile.Levels(I)
Select Case myLeve l. Name
Case "STRE ET"
myLevel . Name = " Level 20 "
Act i veDes i gnFi l e.Le ve l s . Re wri t e
Case "SIDEWALK "
X myLevel . Name = "Leve 1 2l "
ActiveDesignFile.Levels.Rewrite
Case "GUTTER"
myLevel . Name = " Level 23"
ActiveDesignFi l e.Levels.Rewrite
Case "STRIPING "
myLevel . Name = "Leve 1 38 "
ActiveDesignFi l e . Levels . Rewrite
Case "SEWER"
myLevel . Name = "L eve 1 39 "
ActiveDesi gnFile. Lev el s .Rewrite
Case "PHONE "
myLevel . Name = "Leve 1 40 "
ActiveDes i gnFile . Levels . Rewrite
Case "ELE CTR IC"
myLeve l . Name = "Level 41 "
Act i veDes i gnFile .L evels . Rewrite
Case "NA TGAS "
myLevel . Name = "Leve 1 42 "
ActiveDesignFile . Levels.Rewrite
Case "FIBER "
myLevel . Name = "Leve 1 47 "
ActiveDesignFile . Levels . Rewrite
End Select
Next
End Sub
488 I Chapter 21: VBA for CAD Managers I
Does the code work? Of course! It works great! It is fast ! It is amazing! It
is a lot of hard-coded mapping that will be difficult to maintain!
What happens when another level name translation is introduced? You
have to change the code and re-distribute the VBA Projects to everyone
who uses it. Right? Maybe not.
Let's think about what we can do to create a level mapping file that tells
what level to look for and what its new name should be.
If this chapter were about working with databases, we could do the
mapping in a database. If this chapter were about working with
Microsoft Excel, we could do the mappings in Excel. But since these
topics will be covered later, we will read from a simple ASCII text file.
Now for the file format for our level mapping file. Each line in the file
represents one mapping. Each line contains two fields separated by a tab.
The first field will be the old level name, the second field will be the new
level name.
Let's look at the code that makes use of our LevelMap file.
Sub LevelSpecFromFile ()
Dim myFile As String
Dim OldLevel() As String
Dim NewLevel() As String
Dim FFile As Long
Dim txtI n As String
Dim xSplit() As String
ReDim Old Level(O)
ReDim NewLevel (0)
Dim my Level As Level
Dim I As Long
Dim J As Long
myFile = "C: \MicroStation VBA\LevelMap.txt "
FFile = FreeFile
I Cross-Company Standards I 489
Here is the code. It does not matter how many levels are in the text file.
There can be 5 or 5,000 - the code doesn't change.
490 I Chapter 21: VBA for CAD Managers I
TRACKING TIME
Time is money, right? How many times have we heard that? Perhaps the
reason we have heard it so many times is because it is true. One benefit
of learning VBA, is that you can do things many times faster with VBA
than without it.
The concern about spending time in a drawing or working on a proj ect
is different from person to person and is often defined by the
relationship we have with the drawing.
Drafters
A drafter may look at the time spent in a drawing as the basis for how
much money will be paid for the work in the drawing. "The more time
spent in a drawing means more money in the paycheck:'
Another drafter may look at the time spent in a drawing as an indication
of productivity. "I am twice as productive as any other drafter:'
Managers
A manager may look at the amount of time spent in a drawing as an
indication that a drafter or designer needs additional training. Or
perhaps a drafter/designer needs to teach others in the company to be
more productive.
Another manager may look at the amount of time spent in a drawing in
terms of progress on a project.
Accountants
An accountant may look at the time spent in a drawing in terms of how
much money to invoice a customer.
Another accountant may look at the time spent in a drawing for
considering raises and setting salaries.
It doesn't matter what role we play in a company, the basics of tracking
time is the same. And if We are working hard (until our backs ache and
our tired muscles knot), accurate time reporting will always be on our
side.
ITracking Time I 491
So what are the basics of tracking time? Who did what and when? Any
time MicroStation is open, you can find out who is logged into the
computer. Any time you want to capture data, you can get the current
date and time. So the only question you need to answer is "what?". vVhat
events do you want to capture?
Previously, we discussed using interfaces to capture user input, element
selection, etc. You could log each and every command started by the
user. It may be helpful at some point to do a usability study on how
MicroStation is used, but that is probably overkill for what we are
attempting to accomplish here.
You could capture File Open and File Closed events. This would be
useful to know but would be insufficient or misleading, especially for
billing. What if someone opens a file at 4:59 PM on Friday then leaves
for the weekend?
Better to capture something else while the file is open to know if the file
is being worked on. Let's try watching the View Update event. This event
is not triggered so often that logging information will be a performance
problem.
To capture events, you need a new class module. Name it clsTimeTrack.
Here is the code in the class module:
Implements IViewUpdateEvents
Dim WithEvents MSApp As Applicat i on
End Sub
Cl ose #FFile
End Sub
Let's look at the events we are capturing:
As the code suggests, we write our time logging data into an ASCII text
file and give each captured event a four-letter abbreviation, such as
"INIT", "TERM", "REDR", "CLOS", and "OPEN': This tells us what
happened at the date and time specified. A tab character separates each
field in the text file .
Since the code is written in a class mo dule, use code in a code module to
call up the class so the class can capture the events.
. ..
.:;
Make a small change to log the full path of the DGN file. Instead of
splitting the file name given to us, use the parameter "DesignFileName"
in your print statement.
Sub OnProjectLoad ()
TestTimeTra ck
End Sub
I Auto-Load and Auto-Run I 495
The OnP raj ect Load feature in MicroStation VBA is easy to use. Enter the
procedure named "OnProjectLoadO", then anything placed in the
procedure will be executed when MicroStation starts.
Of course, even though OnProj ectLoad is an incredible feature, use it
with restraint. VBA does not ask what the code inside OnPraj ectLoad is
doing. It just begins executing it. If we have code that begins processing
data, opening and closing files and a host of other things, it could cause
problems. The result could be that, when a user starts MicroStation, it is
executing code placed in an OnProjectLaad procedure in an AutoLoad
Project but looks as though MicroStation has locked.
After saving your project, exit out of MicroStation. Opening
MicroStation again causes the IN IT event to be logged into your logging
file.
So, at this point the code works on your development machine. Imagine
being so excited about this new project that you immediately place it on
a shared drive so everyone can begin using it today. You go from
machine to machine, load the project, and set it to AutoLoad. You don't
tell the users why you are doing this, but ask them to shut down and
restart MicroStation. One by one, you do this but all of a sudden
something happens.
Windows allows us to share a folder and we can also share a file. But
when more than approximately 20 people attempt to open a file at the
same time, Windows begins to complain. So how do you support 100
users? Place the VBA Proj ect on their individual machines? No. Please,
no.
all Opens all VBA Projects in memory. This remove s the 20-user
limit and prevents users with this setting from editing
existing VBA Projects because they wi ll only be in memory.
readonly Opens ReadOnly VBA Proj ects in memory. ReadWri te
Project s are opened fro m fil e.
none VBA Projects are never opened in memory. All projects are
opened fro m f il e.
Cqf!figl!r!l~ton ~; lIJie,~ [!l!1titled]" " " ,,,,' " " ',' ," p,' '." ""~' " , , " ,'. ' ,
File . , ' , .
'1
~i ~_~~~;~:_';';J l:!-
~: !I
Fo-r -mo-re- o·-Pt-io-ns-
L . c-lic- k-o-n-th-e -ca-te-go-rY- Ii-st-at-le-n-, - - - - - - - - - - '
"~VO~ [ .,_
~
y_________.
___..--1
E:<pansion: readonl;-------------------P---·------··-t
A~rt ,
Click Yes to save the configuration file. Files marked as "ReadOnly" will
be opened in memory.
498 I Chapter 21: VBA fo r CAD Manage rs I
Marking a file as ReadOnly is simple. First unload it in the VBA Project
Manager. After the file closes, browse to it in Windows Explorer, right-
click on the file, and select Properties.
---~===~
Location: C:\Documents and Settings\AII Users\Application C
Created:
Modified:
Accessed:
----------------------
Attributes: [AI;!vanced ... I
r OK . I[ Cancel Ii 8Ppl/ I
PROTECTING PROJECTS
Normally, we discourage writing passwords on pieces of paper. Why?
Because we don't want anyone to find the paper and discover the
password. Although the concept of protecting password is correct,
forgetting a password to a protected project can be ... can be ...
hmmmmm, well, devastating.
Password-protecting a finished project is a good idea. Whether we are
managers or marketers, we don't want our hard-earned code to be
available to just anyone.
I Protecting Projects I 499
ettings\AU Us~rs~ppl!!=d!io~~
Project Properties. ~ Add-Ins Window Help
(t. B.eferences...
The Properties menu item is
f!.ddi\:onal Controls ..
different from project to project. [:1acros ...
General [£~~IfL_--_-----------
_._-_ . _ -------------_.._______1
~ . OK . :11 Cancel I[ Help I
Two tabs appear. Use the first, General, to give your project a name
and description. The Help and Compile areas are outside of the
scope of this book so we won't discuss them here.
500 I Chapter 21: VBA for CAD Managers I
Use the Protection tab
to set the Project's
~ Protection 1<--___________--,
password.
' Lock project
Each selected reference refers to a .dll or .exe file with functionality for
use in our programming. The top three items appear in every
MicroStation VBA project. We added the Microsoft Scripting Runtime
library earlier in the chapter. Before distributing projects, look at the
references added to the project because their absence on someone else's
computer will cause problems.
For example, while working with Microsoft Excel we add a reference to
the "Microsoft Excel 11.0 Object Library". This helps us develop more
quickly and accurately as we work with Excel. The program works great
on our development machine but, when placed on a computer without
Microsoft Excel installed, strange things happen (and not just with
502 I Chapter 21: VBA for CAD Managers I
regard to the Excel code). Functions such as UCase, LCase, Trim, etc.,
display errors telling us their library is not loaded.
flvailable References: OK
D Ali Cancel
D Microsoft Exchange Event Service Config 1.0 Type Li '~i
D Microsoft FrontPage 4.0 Page Object Reference Lib" :
D Microsoft FrontPage 4.0 Web Object Reference Librc '', Browse".
D Microsoft Graph 11.0 Object Library
D ~licrosoft H323 Service Provider I. a Type Libr ary
D Microsoft Help Data Services 1.0 Type Library
i
i-.!J
!
D Microsoft HT~IL Object Library ~'I Priority
D Microsoft InkDivider Type Library, version 1.5 j Help
D Microsoft InkEdit Control 1.0 -+ I I
D Microsof t Internet Controls ...:J
D ~Iicrosoft IP Conf erencing Service Provider 1.0 Type '
DMicrosof t Jet and Replication Objects 2.6 Library
n Mirrn.:;;nft I TSrnmmnn OhiArt I ihr ?rv
-, i
6 11
lIll!::~.:.·~.~,:;.:~~~::}~J~r,:·:,,~"~·,~,>,~~:,;.·.~,::J ,,~~l_i !
, Microsoft Excel 11.0 Object Library
So, when distributing VBA Applications, make sure you know exactly
which references are selected and let users know what they need to have
installed for your program to work correctly.
'CD" The proieet could not be loaded because its digital signature could not be verified.
REVIEW
From a CAD manager's point of view, VBA can do a lot to aid in
maintaining CAD standards. Productivity is important to maintain and,
at times, measure. Securing VBA projects means getting productivity
from the VBA projects and keeping wandering eyes from playing with
your code. Auto-load and auto-run code is powerful and easy to
implement. The most difficult thing is knowing when to use these
powerful features to your best advantage.
504 I Chapter 21: VBA for CAD Managers I
22 MicroStation File-Based
Events
You can execute code whenever a specific event happens, such as writing
a file name to an ASCII text file each time a file is opened. This chapter
deals with MicroStation file-based events using some very powerful
programming techniques.
We looked briefly at two of these events in Chapter 14 but will cover
them in detail here.
In this chapter:
[B The "OnDesignFileOpened" event
[B The "OnDesignFileClosed" event
[B The "ISaveAsEvents_BeforeRemap" event
[B The "ISaveAsEvents_AfterRemap" event
[B The "ISaveAsEvents_AfterSaveAs" event
50S
506 I Chapter 22: MicroStation File-Based Events I
ONDESIGNFILEOPENED
The OpenDesi gnFi 1eOpened event is part of the MicroStation Application
Object. Each time a design file is opened, the OnD es i gnFi 1eOpened event
is triggered. Let's add some very simple code to this event.
To begin, this event is only available when a variable is declared as an
''Application'' type of object using the "WithEvents" keyword.
Create a new class module and name it clsSaveAs.
Writing the code is simple but you cannot execute the code in an event
in the same manner as when you place code in a code module. We will
discuss how we get a class "up and running" later in the chapter.
I OnDesignFileClosed I 507
ONDESIGNFILECLOSED
This event is triggered when a file is closed. Your code could write to an
ASCII file just as it did with the OnDes i gnFi 1eOpenec event but there are
far more powerful and useful things you can do.
Let's brainstorm on what to do with the OnDesign Fi l eCl osed event. A
user closes a file in MicroStation. Is it the end of the day? Is this the last
time the file will be opened this week? What changes were made while
the file was open? Who was using the file when it was closed? What time
was it closed? Had the file been opened earlier in the day?
We could write 100 different applications using the OnDes i gn Fi 1eC 1osed
event but let's pick one: capture a file when it is closed. Of course, you
can copy the file to a folder but that could take more hard drive space
than should be dedicated to this purpose. If you zip (compress into a .zip
file), you would save some disk space. If you place the file in an existing
zipped folder or file, this may be even more helpful.
So, how do you compress multiple MicroStation DGN files into a single
zip file? VBA is not supposed to be that powerful, right? Well, we could
spend money on a third-party DLL or ActiveX Control, but do we want
to spend money when we don't need to?
Windows XP introduced compressed (zipped) folders, essentially a zip
file (.zip extension) that Windows treats as a folder. You can copy files to
and paste from a compressed folder using standard Windows
functionality. Let's leverage this new Windows XP functionality to zip
files using VBA.
Before you write any code, add a reference to the "Microsoft Shell
Controls and Automation" object in VBA (Tools> References). This
gives you access to some powerful features developed by Microsoft for
developers (in this case, we are the developers). The Shell32.dll Object
can do a lot of things. We will only scratch the surface as we discuss a
couple of events in this chapter.
As you will see later in this chapter, it is easy to add files to an existing
zip file (compressed folder); but if the file does not exist, we need to
create it.
Nearly all files we use on a daily basis have two identifying features. The
first is the file extension. For example, we instinctively refer to a file with
a .dgn file extension as a MicroStation file but there is nothing keeping
508 I Chapter 22: MicroStation File-Based Events I
us from changing the file extension of a .txt file to .dgn. So, even though
the file extension is a good indication of file type, there are no
guarantees. The second identifying feature is the file header, consisting
of a specific number of bytes at the beginning of a file, that helps
programs verify the file type.
A zip file (or a compressed zipped folder) header consists of 24 bytes.
How do we know this? Create a new zipped folder in Windows, then
open the file in a Hex editor to see the byte values of each byte in the file.
The first four byte values in a zip file are 80, 75, 5, and 6. The next 20
bytes have byte values of 0 (zero). So, we can create an empty zip file by
writing Chr(80), Chr(75), Chr(5), Chr(6), and then 20 Chr(O) values.
This writes a zip file header to a file which Windows XP recognizes by
file extension and by file header. Other zip file readers/writers also
recognize the file as a legitimate zip file. Of course, a zip file is not very
useful if it is empty.
After the zip file is created (if it did not already exist), you can copy files
to the 'file/folder' by using the Shell library.
Place the procedure CopyFi 1eToZi pFi 1e in the class module, not the code
module.
Kil l CopyFileAs
Else
zipFolder.CopyHere CopyF i leAs
End If
End Sub
The first thing we do is check to see if the .zip file exists. If not, we create
the file and print to the file using standard File I/O (Input/Output)
commands we have used multiple times in this book.
Our function Copy Fi 1eT0Zip Fi 1e allows us to specify the file to copy and
the file name to use inside the zip file. Later you will see why this ability
to specify the file name used by the .zip file is important. The variable
myShell is declared as a "New Shell" object. This exposes the referenced
object's methods, properties, and events. We use the zip file name to get
a folder using the Namespace method of the shell object. If the
FileToCopy variable is not the same as the CopyFi leAs variable, we copy
FileToCopy to CopyFileAs, and then copy the CopyFileAs file to the zip
file . The last thing to do is kill (delete) the file. If, however, the
FileToCopy variable is the same as the CopyFi leAs variable, simply copy
the design file to the zip file without doing any other copying or killing
(that function sounds so violent, doesn't it?).
NOTE: The web page at http://www.codeproject.com!csharp/
Decompress WinShellAPICS.asp describes using the shell object to
work with Windows XP's Compressed (zipped) folders.
The CopyF i 1eToZi pFi 1e procedure is now ready to be used by the
OnDesi gnFi 1eCl osed event.
ISAVEAsEvENTSINTERFACE
The ISaveAsEvents interface includes ISaveAsEvents_BeforeRemap,
ISaveAsEvents_AfterRemap, and ISaveAsEvents.
The ISaveAsEvents_BeforeRemap event is a member of the
ISaveAsEvents interface. To use members of an interface, we declare the
interface in our class module. Here is the declaration we need to put into
the class module with which we have been working:
Implements ISaveAsEvents
As in previous discussions on interfaces, we need to declare all events
(methods) of the interface before putting code into any of them.
End Sub
End Sub
End Sub
IISaveAsEvents Interface I 511
Di m Fi l eSave d As Str i ng
Dim Fi le Form at As Long
Di m Fil ePre vi ous As Strin g
Now that the variables are declared, they can be used in the Aft er Remap
event as follows:
So, how do we get files into this temporary storage location? Where is it?
Let's use the shell object we just finished working with in the last
example in this example.
We need to create a new procedure in the class module we used in the
previous example. This procedure is named CopyFi 1eto CD and it takes
one parameter, the file that is to be copied to the CD. Here's the code, a
discussion follows.
The first thing we do is fin d the temporary storage location for the user
who is logged in. Now, how do we do that? We supply the number 59 to
the Namespace method of the shell object. If we do this and the returned
folder is not "Nothing" (in other words if the folder is found), we copy
the supplied file into the cdFolder. That's all there is to it.
One of the great things about this procedure is that we don't need to
purchase CD writing add-ins. If the user has Windows XP, we can use
this procedure.
Remember that the CopyFi 1eToCD procedure
does not actually burn the CD - it only
copies the file to the staging area to burn the ~.. ¥~ _~~ ~~v • ~ v
~ OVO/CO-RW.Orive (0:) .
CD. When you are ready to burn the CD,
place a CD- R or CD- RW into the CD burner,
select the CD drive in Windows Explorer, and
go to the Explorer menu File > Write these
files to CD .
These menu picks begin the process of writing the files in the temporary
CD folder to the CD.
So we now have code that prepares files to be written to a CD. How do
we use it? We use it in the ISaveAsEvents_AfterSaveAs event.
Implements ISaveAsEvents
FileSaved = DestinationFilename
FileFormat = SavedFormat
FilePrevious = TheDesignFile . FullName
End Sub
! ISaveAsEvents Interface ! 515
End Sub
REVIEW
In this chapter, you zipped files (compressed them) and prepared them
for burning to a CD using Windows XP. You can accomplish the same
tasks in other operating systems but would need to program differently.
You now have the knowledge to execute code when the user performs a
SaveAs or when a file is opened or closed no matter what the operating
system or the desired functionality.
Before beginning any project, take time to think through the
functionality you want in the project. Think about the best possible
program. Don't limit yourself because you are unsure how to accomplish
a task or two, or three, or more. Even the oldest dogs can learn new
tricks - in this case, VBA tricks.
518 I Chapter 22: MicroStation File-Based Events I
23 Responding to
MicroStation
Attachment Events
In this chapter:
[B The IAttachmentEvents Interface
[B After Attach
[B After Detach
[8 AttachmentModified
[8 BeforeAttach
[8 BeforeDetach
519
520 I Chapter 23: Responding to MicroStation Attachment Events I
THEIATTACHMENTEvENTSINTERFACE
Let's create a new class module named clsAttcchmentEvents. You must
declare each event implem ented by the IAttachmentEvents interface.
Add simple Debug.Print statements inside each event to help us
understand the order in which events are triggered.
Priv ate Sub IAtt ach me nt Event s_A ttachm entModified ( ByVa l _
TheA t ta c hment As At t achme nt )
De bu g . Prin t "Att ach ment Mod i f i ed"
End Sub
AFTERATTACH
Private Sub IAttachmentEvents_AfterA t tach(ByVa l _
TheAttachment As Attachment)
End Sub
I AfterAttach I 521
After a DesignFile is attached to the current design file, the After Attach
Event is triggered. When this event occurs, we can be certain the file is
actually attached and is available for processing. The parameter
"TheAttachment" is provided in the event so we can begin working with
the attachment immediately.
The "TheAttachment" Parameter is declared as an Attachment type of
Object. Perhaps understanding this object a little better will help us to
know what we can do with this event. The list is several pages long so we
will just take a look at a few of the properties and methods.
[B Sub AddElement(Element As Element)
[B Sub AddElements(ElementsO As _Element)
[B Property AttachName As String {read-only}
[B Property Description As String
[B Property DesignFile As DesignFile {read-only}
[B Property DisplayFlag As Boolean
[B Property Is3D As Boolean {read-only}
[B Property IsActive As Boolean {read-only}
[B Property IsReadOnly As Boolean {read-only}
[B Property IsTrueScale As Boolean {read-only}
[B Property Level As Level
[B Property Levels As Levels {read-only}
[B Property LogicalDescription As String
[B Property LogicalName As String
[B Property MasterOrigin As Point3d {read-only}
[B Sub Move(Offset As Point3d, ApplyToClipElement As Boolean)
[B Property Name As String
[B Function Reattach(FileName As String, ModelName As_
String) As Attachment
[B Sub Redraw([DrawMode As MsdDrawingMode =_
msdDrawingModeNormall)
522 I Chapter 23: Respond ing to MicroStation Attachment Events I
[8 Sub Rem oveElement(Element As Element)
[8 Sub RewriteO
As you look at these properties and events, think about how to use them
AFTER the attachment is attached.
Let's look at the DesignFile property. When an attachment takes place,
we can get the DesignFile of the attachment and get the DesignFile's
path. Let's add a Date/Time stamp with the attachment's file name to the
active model.
the first attachment or the hundredth. We could add code to change the
position of the Text Insertion Point, etc., but we will move to another
example that uses the AfterAttach Event.
AFTER DETACH
Two events relate to detaching attachments: Before Detach and After
Detach. The After Detach event is you last opportunity to do anything
with the attachment. Let's try some code that could notify someone an
attachment has been detached.
ATTACHMENTMoDIFIED EVENT
The AttachmentModified Event gives us the same information as the
AfterAttach and AfterDetach events. We are given the parameter
"TheAttachment" with which to work. This event may be useful to track
changes made to an attachment but will not help us with the nature of
the modification. We need to look at additional events to get more
detailed information on that.
BEFOREATTACH EVENT
Pr i vate Sub IAttac hme ntE vents_BeforeAttach(FileName As Str i ng . _
AllowA tt ac hment As Boo l ea n )
The BeforeAttach Event is triggered before an attachment takes place.
We are supplied with the FileName and given the opportunity to cancel
the attachment by setting the AllowAttachment parameter to False.
Pr ivat e Sub IAttachm en t Events_Be f oreA t tac h( Fil e Name As Stri ng.
All owAttac hme nt As Boo l ea n)
If Ge t Att r( FileName) And vbReadOn l y Th en
MsgBox "Attaching Read-Only Files is Prohibited. "
AllowAttachme nt = Fa l se
End If
End Sub
In this example, if the file that is being attached is set as ReadOnly, we
show a MessageBox stating that attaching read-only files is prohibited.
After the MessageBox, we set the AllowAttachment parameter to False.
This means the user is not shown the attachment dialog box. If an
attempt is made to attach a file and the file is not read-only, we do
nothing and the Attach File procedure continues.
526 I Chapter 23: Responding to MicroStation Attachment Events I
BEFOREDETACH EVENT
Private Sub IAt~achmentEvents_BeforeDetach(ByVal _
TheAttachment As Attach~ent)
REVI EW
The ability to attach files to an existing design file is powerful. It allows
us to design more quickly and with fewer errors. Accuracy is improved
because we can look at an entire design at one time. Do the walls line up
with the foundation? Using the IAttachmentEvents Interface allows us
to intercept events so we can track which files are being attached,
detached, and modified.
24 Model Events
The last chapter dealt with Attachment Events; this one deals with
model events. Two separate interfaces expose Model-related events:
IModelActivateEvents and IModelChangeEvents. We will implement
both interfaces in the same class module, clsModelEvents.
In this chapter:
[B The AfterActivate event
Implements IModelActivateEvents
Implements IModelChange Events
527
528 I Chapter 24: Model Events I
Pri vate Sub IM ode lAc ti vat eE vent s_Be fo re Ac tivate
( ByV al TheM odel As Model Reference )
Debug . Pr i nt "BeforeActivate : " & vbT ab & _
TheMode l. DesignFi l e . Name & vbTab & Th eModel.Name
End Sub
' Active
Case Ms dMode lChangeType.mdlModelChangeBeforeActive
ModelChange = "BeforeActive "
Case MsdModelChangeType.mdlModelChangeActive
ModelChange = "Active"
' Create
Case MsdModelChangeType.mdlModelChangeBeforeCreate
ModelChange = "BeforeCreate "
Case MsdModelChangeType.mdlModelChangeCreate
ModelChange = "Create "
' Delete
Case MsdModelChangeTy pe.mdlModelCha ngeBeforeDelete
Mode lCh ang e = "B efore Del ete "
Case MsdMode l Change Type . md l Mode l Change Dele t e
ModelC hange = "Delete "
' Name
Case MsdMode l ChangeType.mdlModelChangeBeforeName
ModelChange = "BeforeName "
Case MsdMode l ChangeType . mdl ModelChangeName
ModelChange = "Name "
' Properties
Case MsdModelChangeType . mdlModelChangeBef orePr operties
ModelChang e = "Bef oreProperties "
I Model Events I 529
'Settings
Case MsdModelChangeType.mdlMode l ChangeBeforeSettings
ModelChange = "BeforeSet t ings "
Case MsdMod el ChangeType . md lM odelChangeSett i ngs
Mode lC hange = "Settings"
' UnCreate
Case MsdModelChangeType.mdlModelChangeBeforeUnCreate
ModelChange = "Be foreUnCreate "
Case MsdModelChangeType.mdlModelChangeUnCreate
ModelChange = "UnCreate "
' PropagateAnnotationScale
Case
MsdModelChangeType.mdlModelChangePropagateAnnotationScale
ModelChange = "P ropagateAnnotationSca l e "
End Select
End Function
The function "ModelChange" receives a constant value and converts it
to text. This makes it easier to see what is taking place. As with other
interfaces, the class module must be instantiated in a code module:
Sub AddEvents ( )
RemoveEvents
Set myME = New cl sModelEvents
AddMode l ActivateEventsHandler myME
AddModelChangeEventsHandler myME
End Sub
530 I Chapter 24: Model Events I
Sub RemoveEvents( )
If myME I s Not hing = False The n
RemoveModelActivateEventsHandler myME
RemoveModelChangeEventsHandler myME
Set myME = Nothing
End If
End Su b
When a model is switched in a design file, we see the followi ng results in
the Immediate window:
f l angedval ve .dgn
fl angedval ve.dgn Untitled Sheet - BeforeActive
Af te rAc ti va te : f l ange dvalve . dgn Untitled Sheet
Change : f l angedvalve.dgn Untitl ed Sheet - Activel
Be fo reActiva t e: fl angedvalve .dgn Model -l
Change: flangedvalve.dgn Model-l - BeforeActive
AfterActivate: flangedvalve.dgn Model-l
Change: flangedvalve.dgn Model-l - Active
IMode l ActivateEvents_BeforeActivate
IModelChangeEve nts_ModelChange (With Be f oreAc t ive Eve nt )
IModelActivateEvents_AfterActivate
IModelChangeEvents_ModelChange (W i th Active Event)
Each event supplies a ModelReference so we know which model is about
to be activated. The ModelChange event is triggered twice when the
active model is being changed. First, we get a Mo delChange event with
the "BeforeActivate" constant and then a ModelChange event with an
''Active'' constant.
REVIEW
Like other events, model events are implemented through an interface.
Something as simple as adding Debug.Print statements can help us
understand how, when, and why events are triggered. A little creativity
and some VBA know-how can result in the creation of powerful
solutions.
25 Level Events
531
532 I Chapter 25: Level Events I
Although the change type names are self-explanatory, we had better
look at the actual event before continuing.
End Sub
Three parameters are passed to us in the LevelChanged event. The first
gives us the type of change. This is provided in the form of an
enumeration constant. Values for the ChangeType parameter are:
MsdLevelChangeType.msdLevelChangeAfterChangeActive = 9
MsdLevelCh ange Typ e. msd Lev elCh ange Af t erCreate = 2
Msd LevelChangeType.msdLevelChan ge AfterDelet e = 3
Msd Level Ch ang eType .msdLe ve l Change Befo re ChangeAct i ve 17
MsdLeve lC hangeType .ms dLevelC hangeBef oreDelet e = 18
MsdLevelCh angeType.msd LevelChange Cha nge At tr i but e 8
MsdLevelC ha ngeType .msdLeve l Chan geChan geCod e = 5
MsdLevelCha ngeType .msdLev elCha ngeChan ge Displ ay = 7
MsdLeve l ChangeType .msdL eve lChangeCh ange Na me = 4
MsdLeve lC hangeType.msdL evelChangeChang ePar ent = 6
Msd LevelC hang eType. msdL eve l Chan geTab l eRe do 15
Msd Level Chan geType .msdLevelCh angeTabl eUndo 14
Let's begin by using a function to convert the constant provided to a
string and a simple Debug.Print statement. This allows us to implement
the interface and experiment with it to see when and how Level events
are handled.
REVIEW
Every model uses levels as they are critical to organizing our design files
and models. Knowing when levels are modified can be helpful especially
when we are dealing with standards.
26 Change Track Events
In this chapter:
[B The BeginUndoRedo event
[B The ElementChanged event
BEGINUNDOREDO EVENT
Private Sub IChange TrackEvents_BeginUndoRedo( _
ByVal AfterUndoRedo As El ement. _
ByVal BeforeUndoRedo As Element. _
ByVal Act i on As MsdChangeTrackAction.
ByVal IsUndo As Boo l ean)
End Sub
The Begin Undo Redo event is triggered before any undo or redo.
'AfterUndoRedo' points to the element with all of its properties after the
Undo or Redo action. The 'BeforeUndoRedo' parameter points to the
element with all of its properties before those actions. The 'Action'
537
538 I Chapter 26: Change Track Events I
parameter tells which type of action has taken place. 'IsUndo' helps us
know whether the action was an Undo or a Redo. Let's look at some
code in this event:
End Sub
In this example we write the Level Names of the elements that are
modified, Action, and IsUndo parameters to the Immediate window.
For example, if we change the level of an element, and then issue an
Undo and then a Redo, we see the following lines in the Immediate
window:
,Vii
....{ ."
\£,;1
We can see the After and Before Level names, the Type (3), and the fact
that the first action was an Undo and the next one was a Redo (based on
True and False values). The Level names and Undo/Redo values make
perfect sense. But what about the number 3? It tells us the Type of event.
Right? The value points to an item in the MsdChangeTrackAction
enumeration.
msdC hangeT ra ckAc ti onAdd = 2
msdChangeTrackActionAppData = 8
msdC hangeTrackAc ti on Delete 1
msrlC hange TrackAc ti on Drop = 6
ms dChangeTrackAct i on Mark = 7
msdChangeT rackAc ti onModelAdd = 9
msdChangeTrackActionModelDelete 10
msdChangeTrackActio nModify = 3
I Element Chang ed Event I 539
End Sub
Whenever an element changes, the ElementChanged event is triggered.
The parameters provided in this event are very similar to the
BeginUndoRedo event. We are given a reference to the element before
and after the change is made, the type of action, and whether the action
can be undone.
Let's look at several implementations of the ElementChanged event:
End Sub
540 I Chapter 26: Change Track Events I
The code is simple and straightforward. When an element is modified,
we are given the element before and after it is modified, the type of
action, and whether or not the action can be undone.
Here an element's level was changed from "Default" to "New Level (0)"
to "New Level (1)" and back to "Default". Each action type is 3 and the
actions can be undone because the "CantBe Undone" parameter is
passed to us with a value of False.
The Change Type is 3. A review of the constants in the
MsdChangeTrackAction enumerator reveals that we are dealing with a
"msdChangeTrackActionModify" action.
Let's build on the event by adding more code:
End Su b
I Element Changed Event I 541
<, >
Example 1
Private Sub IChangeTrackEvents_ElementChanged(
ByVal AfterChange As El ement. _
ByVal BeforeChange As Element. _
ByVal Action As MsdChangeTrackAction.
CantBeUndone As Boolean)
End Sub
When an element is modified, we check to see if it is a TextNode or Text
element. If it is one of these types of elements, we check what level the
element is on. If it is not on the "TEXT" level, we place it on the "TEXT"
level and Rewrite it so the change is saved to the file.
I Element Changed Event I 543
Example 2
Private Sub IChangeTrackEvents_E lementCha ng ed (
ByVa 1 AfterChar.ge As El ement. _
ByVal BeforeChange As Element. _
ByVal Action As MsdChangeTrackAction.
CantBeUndone As Boolean)
End Sub
Add : 15 0 13 6
Ad d: 6 0 13 7
Ad d: 'I 0 138
(: J
Knowing what type of element is added can come in handy. Let's add a
function so we can see the type of element as a description instead of a
number. We will modify the event to use this new function.
End Sub
End Sele ct
End Func ti on
< 1 >:
Example 3
When an element is deleted, the action recorded is
'msdChangeTrackActionDelete'.
End Sub
548 I Chapter 26: Change Track Events I
Text Deleted
Shape Deleted
Ellipse Deleted
Line Deleted
Line Deleted
<1: J
Example 4
We had several examples using the 'Action' parameter instead of
counting on the 'CommandName: Our next example uses both.
Se t myLev el = _
Ac t iv eDesign File .L ev els( Leve l Coun t - 1)
Debug.Pr int myL eve l .Na me & " Added . "
End Select
End Select
End Selec t
End Sub
Sub RemoveEvents ()
If myCTE Is Noth i ng False Then
550 I Chapter 26: Change Track Events I
RemoveChangeTrackEventsHandler myCTE
Set myCTE = Nothing
End If
:::nd Sub
REVIEW
You can use the ChangeTrackEvents interface for a thousand different
purposes. Fortunately, it usually takes only a little experimentation
before you can implement it and get the results you need.
27 Non-Graphical Info -
Databases
We can store data about design file elements in a database instead of in
design files. This makes the design file smaller and the file element
information available outside of the MicroStation environment.
This chapter focuses on MicroStation's Database Link functionality. A
later chapter discusses additional ways to work with databases.
In this chapter:
[8 Linking MicroStation elements to databases
[8 Creating a Microsoft Access database from scratch to link to a
design file
[8 Using UDL (Universal Data Link) files
[8 Linking elements in MicroStation to a database using VBA
[8 Creating database records using SQL
[8 Creating a user interface to view database information
551
552 I Chapter 27: Non-Graphical Info - Databases I
EntnyNumber
[sin formation
Mslink
.. - -........ -.......... ,
..... -.-.. -. •.1-
Sub CreateDB()
Dim myCat As New ADOX.Catalog
Dim dbLocation As String
Dim ConnString As String
dbLoca t ion = "C: \MicroS t at ion VBA\DatabaseLinkTest . mdb "
ConnS t r i ng = "Provider=M i croso f t . Jet.OLEDB.4.0 ; Data Source= " &
dbLocat i on
myCat . Create ConnStr i ng
End Sub
This code uses the "Microsoft ADO Ext. 2.8 for DDL and Security"
Reference. Before executing the procedure, you need to add this
Reference in VBA. This code creates a new database. The database is
empty; there are no tables in it. Our next step is creating tables.
Although there are many ways to add tables to an existing database, we
will discuss three of them.
I Creating a Database from Scratch I 555
One way to add tables to an existing database is to use the same ADOX
reference we just used to create the database.
Sub CreateDB2()
Dim myCat As New ADOX.Catalog
Dim dbLocation As String
Dim ConnString As String
dbLocation = "C:\MicroStation VBA\DatabaseLinkTest . mdb "
ConnString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" &
dbLocation
myCat . ActiveConnection = ConnString
Dim myTable As New Table
Dim myColumn As ADOX . Column
myTable.Name = "Lots "
'mslink Colu mn
myTable . Columns.Append "mslink " , adlnteger
' Owner Co lu mn
Set myCo lumn = New ADOX . Column
myColumn.Name = "Owner"
myColumn.Type = adVarWChar
myColumn.Attr i butes = adColNu l lable
myColumn . DefinedSize = 50
myTable.Columns . Append myColumn
'DateSold Column
Set myColumn = New ADOX . Column
myColumn.Name = "DateSold "
myColumn.Type = adDate
myColumn . Attributes = adColNullable
myTable.Col umns.Append myColumn
myCat.Tables.Append myTable
myCat.ActiveConnection = Nothing
End Sub
When we create the "mslink" column, we append the columns collection
in-line. When we create a column in-line, we do not have as much
control over the properties of the column (field). For example, you may
or may not want a field (column) to be required. If you do not want a
column to be required, you specify the Field's Attributes property as
<adColNullable'. This means the column can have a value of <null'.
The second way you can create a table is to use the "ActiveX Data
Objects Library" reference. You need to add a new reference before
running the procedure Cr eateDB3. When you open the references dialog
box to add "ActiveX Data Objects" as a reference, you may see several
libraries to choose from. You should select the highest version of the
library available.
In this example, we will execute an SQL Statement on the database to
create a new table named "Expenses". Here is the example:
Sub CreateDB3()
Dim myDB As New ADODB.Connection
Dim dbLocation As String
Dim ConnString As String
dbL oc ation = "C: \ MicroStati on VBA\DatabaseLinkTest.mdb "
ConnString = "P rov ider=Microsoft.Jet.O LEDB .4.0;Data Source=" &
dbLocation
myDB.Open ConnString
myDB.Execute "Create Table Expenses (mslink Coun ter, " & _
"LotLink Long, Description Char(lOO) , Amount Double) "
End Sub
I Creating a Database from Scratch I 557
When I created the mslink field, I gave it a 'Counter' type. This causes
the field to be an auto-number field that automatically assigns a numeric
value to this field each time a new record is created. The value for this
field begins with one (1) and increases by one each time a new record is
created. The auto-number field type is not available in all databases but
it is available in Microsoft Access databases.
The last method uses the MicroStation Visual SQL Query Builder. Use
the Query Builder to get information out of databases that are
connected to MicroStation and to execute standard SQL statements on a
connected database.
Before using the Query Builder, connect to the database. Before
MicroStation can connect to a database, it needs to know the type of
database and where the database is located. One of the best ways to
provide this information is through a UDL file.
In MicroStation, select the menu Settings> Database> Connect.
Q.esign File",
level
loc!>s
Cam!lt'a
B.endering ~ Q.uery Builder
~ Verify l,inkages
2.naps
'/jew Attributes Ctrl+B
558 I Chapter 27: Non-Graphical Info - Databases I
The Database Connection dialog box opens:
~l'-:' (,','" , ~ }~" ~"~' . '" ,~,,~ ~ ... ~~ "'.,
Browse ~ I
.
,.~;'J?t7: tY1f~~;0?:''','~~-'r.,:r_~ Sij,,~ 'f;~~f ,<,~"n:;"" w~
After selecting OLEDB from the
:!JP~ w[l!~P~T,~/ '~'!Xi;,~·~~,<~ '~v)f;' h~~Ni~t~.i1'~~'ti~: ~y; database server, select New from
i@:c.I;J~~:~~~::j I 0 atabaseLink Test I the Database Source combo box.
~ Cancel I
When you select New, a new UDL file is created and you are asked to
enter the UDL file parameters.
!::lext» ~
~ . T~~i C:~~n~qij~n J
~
OK I[ Cancel I[ Help
o Dataset Mode
Functions:
i Value .9_1 _ __ _ ___ ~J
o Execute Query on Open
TaQ!es o No Duplicate Rows
o Append to Dataset
SQL 5 elect 5 tatement
Execute
Clear All
Clear Text
562 I Chapter 27: Non-Graphical Info - Databases I
You can use the Visual SQL Query Builder dialog to get information
from a connected database. When we retrieve information from a
database, we often use the "Select" SQL statement. So, the box we type in
is titled "SQL Select Statement". But you can do much more than simply
select database records in this textbox.
When you type SQL statements in the "SQL Select Statement" textbox
and click the Execute button, the statement entered is executed by the
connected database. Let's create a new table named "History" by
executing a SQL Statement. The History table will store historic
ownership data.
Clear Texl
Here is the statement to create our new :":~} ,~'JZ~·f't,Y~·\.7!4-:W r'·, <""::. . .~"""'~t<, Y"~ri1" oc_
To display the History table in the Query Builder dialog box, double-
clicking on "History" in the list then click the Close button.
Select 1Where I ' r': I Order8y I
History 0
These are the fields mslink ~
Owner
I-
created in th e PurchaseD ate
History t able. SoldD ate
Sub CreateDB3 ()
Di m myDB As New ADODB . Connection
Dim dbL ocati on As Str i ng
Di m ConnString As Str i ng
db Locat i on = "C: \MicroS t ation VBA\DatabaseLink Test . mdb "
Con nString = "Provider=Mi crosoft . Jet . OL EDB . 4 .0; Data Source= " &
dbLocat i on
myDB . Open ConnString
myDB.Execute "Create Table Expenses (mslink Counter. " & _
"LotLink Long . Description Char(lOO). Amount Double) "
End Sub
564 I Chapter 27: Non-Graphical Info - Databases I
In this procedure, we provide a "Location" and a "Connection String" in
the code to connect to a database at a specific location. This
demonstrates that it is possible to work with databases without a UDL
file. But what happens if the database's location or file name changes?
You need to change the code if you have hard-coded the database
connection information in your programs. If you are the only one using
the program, this is not much of a problem. But if multiple people are
using your program, it is much easier to change a UDL file than it is to
change code, especially if you have locked the code in VBA. You can
instruct even the most basic computer user to double-click on a UDL
file and browse for a different database.
We will discuss UDL file usage in greater detail in a later chapter but for
now, just keep in mind that using a UDL file provides the perfect
combination of power and flexibility.
Sub DatabaseLinkA()
Dim myElem As Element
Dim myLink As DatabaseLink
Set myElem = CommandState.GetLocatedElement(True)
Set myLink = CreateDatabaseLink(l . 1. msdDatabaseLinkageOleDb. _
True. 0)
myElem . ArlrlDatabaseLink myLink
myEl em. Rewrite
End Sub
After the DatabaseLink is created, add it to an element in MicroStation.
I Creating Database Records using SQL I 565
Note that you can create Database Links and add them to elements
without a database being attached. In the example above, we create a
Database Link with an MSLink of 1 (one) and an Entity of 1 (one).
Remember, the Entity property points to the table we are to look in (by
referencing the Entitynum field in the MSCatalog Table) and the Mslink
property points to the record in the table.
This code assumes that the MSCatalog table has a record with an
"Entitynum" of 1 and that the table it references has a record with an
"MSLink" of 1.
The following code looks at the selected element in MicroStation and
displays each DatabaseLink attached to it with the Database Link's
properties in a MessageBox:
Sub GetDatabaseLinksA ()
Di m myElem As Element
Dim myLinks() As DatabaseL i nk
Dim myLink As DatabaseL i nk
Dim I As Long
Set myElem = CommandState.GetLocatedE l ement(True)
myLinks = myElem.GetDatabaseLinks
For I = LBound(myLinks) To UBound(myLinks)
Set myLink = myL ink s(I)
MsgBox myLink.DatabaseType & vbCr & _
myLink.DisplayableAttributeType & vbCr &
myL i nk . Enti t yNumber & vbCr & _
256
a myLink . Islnformat i on & vbCr &
1
True my Lin k . Ms 1ink
1
Next
End Sub
------------------~
INSERT INTO Lots (mslink, Owner) VALUES (1. ' Jones Family')
In this example, we create a new record in the table "Lots". The fields
"mslink" and "Owner" are given values of "I" and "Jones Family"
respectively. You can add fields and values by placing them in the
appropriate places. For more information on SQL Statements, see
''Additional Sources" at the end of this book.
Di m MS Li nkI D As Long
I Creating a User Interface to view Database Information I 567
If Is Numer i c( t xt Ac re s.Tex t ) Th en
myRS( "Acres " ) CDbl(txtAcres . Text )
Else
my RS( "Ac res " ) Null
End If
myRS . Update
End If
568 I Chapter 27: Non-Graphical Info - Databases I
End Sub
my RS.Cl os e
myDB.Close
Exit Sub
End If
myRS . Close
End I f
Next I
myDB.Close
End Sub
When the form is initialized, we look at the selected element in
MicroStation, then get the "Lot" information through the DatabaseLink
object. We display the information in the database and allow users to
change values in the TextBoxes and CheckBox. When a user clicks the
Update Database button, the database record is updated based on what
is entered in the form.
REVIEW
Databases store a large variety of information in tables. Database tables
have fields (or columns) defined in them and each record in a table can
have values in these fields.
DatabaseLink objects associate MicroStation elements with database
records. For DatabaseLinks to work with databases, the database must
have a table named "mscatalog". The DatabaseLink Objects are
associated with the specified table through the MSLink property.
Databases are discussed in more detail in a later chapter.
570 I Chapter 27: Non-Graphical Info - Databases I
28 Tags
In this chapter:
lB Getting information from tags based on a selection
lB Getting all tags in a file
lB Working with tagsets
lB Getting all tags of all files in a folder
lB Changing a tag's value
lB Changing multiple tags in multiple files
lB Exporting tag information to a file
571
572 I Chapter 28: Tags I
Sub GetSelectedTagA( )
Dim myTag As TagElement
Dim myE l emEnum As El ementEnumerator
Set myE le mEnum = _
Application . Act i veModelReference . GetSelectedElements
While myElemEnum.MoveNext
Select Case myE lem Enu m.C ur re nt.Type
Case Ms dEl ementType. msd El ement TypeTag
Set myTag = myEl emEnu m. Cur re nt
If myTag Is Nothin g = Fal se The n
MsgBox my Tag . Val ue
End If
End Se l ect
Wend
End Su b
In this example, we create an ElementEnumerator to look at each
element selected in MicroStation. We look at each selected element to
see if it is a tag. If it is, we display the tag's value in a MessageBox.
The tag's value is of great importance to us but there is more to a tag
than its value. Let's expand the macro to include the tag's name.
Sub GetSelectedTagB ()
Dim myTag As TagE l ement
Dim myElemEnum As ElementEnumerator
Set myElemEnum = _
Application.ActiveModelReference.GetSelectedElements
Whi l e myE l emEnum.MoveNext
Select Case myElemEnum . Current.Type
Case MsdElementType . msdElementTypeTag
Set myTag = myE l emEnum . Current
If myTag Is Nothing = False Then
Ms gB ox myTag . TagOefinitionName & vbTa b & myTag.Valu e
End If
End Select
I Getting Information from Tags based on a Selection I 573
Wend
En d Sub
You can use the tag's name to know if the tag's value tells us who created
the drawing, who checked the drawing, or who printed the drawing.
Get Se1ecte dTagB gives more information than the previous procedure
but can be improved upon. Let's get the tag's TagSetName.
Sub GetSelectedTagD ()
Di m myTag As TagElement
Dim s i bTags() As TagElement
Dim myElemEnum As Element Enumerator
Dim I As Long
Set my ElemEnum = _
Application.ActiveModelReference . GetSelectedElements
574 I Chapter 28: Tags I
Wh il e myE l emEnum.MoveNext
Select Case myElemEnum.Current.Type
Case MsdElementType.msdElementTypeTag
Set myTag = myElemEnum.Current
sibTags = myTag.BaseElement.GetTags
For I = LBound(sibTags) To UBound(sibTags)
MsgBox s i bTags (I) . TagSetName _
& vbTab & sibTags(I) . TagDefinitionName
& vbTab & sibTags(I).Value
Next
Exit Sub
End Select
Wend
End Sub
We use GetTags on the selected Tag's BaseElement. GetTags fills an
array composed of tags belonging to an element. We use a For ... Next
loop to look at each tag's TagSetName, TagDefinitionName, and Value.
Sub GetTagsA( )
Dim myTag As TagElement
Dim myElemEnum As ElementEnumerator
Dim myFilter As New ElementScanCriteria
myFilter.ExcludeAllTypes
myFilter.lncludeType msdElementTypeTag
Set myElemEnum = _
Application.ActiveModelReference.Scan(myFilter)
While myElemEnum . MoveNext
Set myTag = myElemEnum.Curren t
MsgBox myTag.TagSetName & vbTab & myTag.TagDefinitionName _
& vbTab & myTag.Value
Wend
End Sub
I Working with Tagsets I 575
Sub GetTagsSetsA()
Dim myTagSet As TagSet
For Each myTagSet In Application.ActiveDesignFile.TagSets
MsgBox myTagS et.Name
Next
End Sub
Now that you know how to identify each TagSet in a file we can look at
each TagDefinition in each TagSet in a file.
Sub GetTagsSetsB()
Dim myTagSet As TagSet
Dim myTagDef As TagDefinition
For Each myTagSet In Application.ActiveDesignFile.TagSets
For Each myTagDe f In myTagSet.TagDefinitions
MsgBox myTagSet.Name & vbTab & myTagDef .Na me
Next
Nex t
End Sub
And now we will perform the same basic function, but we will display
more tag information:
Sub GetTagsSetsC()
Dim myTagSet As TagSet
Dim myTagDef As TagDefinition
576 I Chapter 28: Tags I
For Each myTagSet In App l ication.Act i veDesignFile.TagSets
For Each myTagDef In myTagSet . TagDefinitions
MsgBox "SetName: " & myTagSet.Name & vbCr & _
"TagName: " & myTagDef.Name & vbCr & _
"Prompt: " & myTagDef.Prompt & vbCr &
"Defa ult: " & myTagDef .DefaultVal ue
Next
Next
End Sub
Sub GetFolderTags()
Di m my DGN As Des i gnFi l e
Dim myFSO As New Scripting.FileSystemObject
Dim myFolder As Scripting. Folder
Dim myFile As Scripting.File
Dim myTagSet As TagSet
Dim myTagDef As TagDefinition
Dim TargetTagset As String
Dim myTag As TagElement
Dim myElemEnum As ElementEnumerator
Dim myFilter As New ElementScanCriteria
TargetTagset = "TitleBlock "
Set myFolder = myFSO.GetFolderC"C:\Documents and Settings\" & _
"All Users\Application Data \ " &
"Bentley\WorkSpace\Projects\ " &
"Examples\Building \Dgn ")
For Each myFile In myFolder.Files
I Getting All Tags of All Files in a Folder I 577
Sub ExportFolderTags ()
I Exporting Tag Information to a File I 581
Sub ExportFolderTagsToHTML ()
Dim myDGN As DesignFile
Di m myFSO As New Scripting.Fi l eSystemObject
Dim myFo l der As Scripting. Folder
Dim myFile As Script i ng.Fi l e
Di m myTagSet As TagSet
Dim myTagDef As TagDefinit i on
Dim TargetTagset As String
Dim myTag As TagElement
Dim my ElemEnum As ElementEnumerator
Dim myFilter As New ElementScanCriteria
Dim FFile As Long
FFi l e = Free Fi l e
Open "C:\MicroStation VBA\Tags.htm" For Output As #FFile
Pr i nt #FFile. "<table width=660 border=I> " & vbCr
Pr i nt #FFile. vbTab & "<tr><td></td></tr> " & vbCr
TargetTagset = "TitleBlock"
Set myFol der - myFSO .Ge t Folde r("C: \Documents and Set ti ngs\ " &
"All Users\Application Data\" &
"Bentley\WorkSpace\Projects\ " &
"Examples\Building\Dgn " )
For Each myFile In myFo l der.Fi l es
Select Case myFi l e.Type
Case "Bentley MicroStation Design File"
Print #FFile. "<tr><td colspan=5>" &
myFile.Path & "</td></tr>" & vbCr
Print #FFile. vbTab & "<tr><td>Tag Set Name(/td>" &
"<td>Tag Name</td>" & _
"<td>Value<!td>" &
"<td>ID Hi gh</td>" & _
"<td>ID Low(/td></tr> "
myFile.Path. True)
For Each myTagSet In myDGN.TagSets
Se l ect Case UCase(myTagSet.Na me )
Case UCase(TargetTagset)
my Fi 1t e r . Exc 1ude All Ty pes
my Fi lt er.I nc ludeType ms dElementT ype Tag
Set myEle mEnum = _
myDGN .M odels( l ).Scan (myF i lter)
Wh il e my El em En um . Mo veNex t
Set myTag = myElemEnum . Current
Print #FFi l e . vbT ab & "<t r ><td> " &
myTag.TagSetName & "< l td>" &
"( td)" & myTag .T agDefinitionName & _
"(ltd)" &
"(td)" & myTag.Val ue & "(l td ) " & _
"(td) " & myTag . IO.High & "(ltd) " & _
"(td)" & myTag . ID.Low & "(/td)(/tr) " & vbCr
Wend
End Select
Next
myDGN . Close
End Select
Next
Print #FFile. "</table>"
Close #FFile
End Sub
REVIEW
Tags contain useful information. The ability to access tags through VBA
gives us control over tags in the active design file but also in every file in
a specific folder and so forth. It is easy to read change values, as you have
just seen. Exporting tag data into ASCII files allows us to work with the
data or view it in other programs such as Notepad and a web browser.
I provide an example of extracting tag information into Microsoft Excel
in a later chapter. You could also extract tag information to a database or
use it as the body of an e-mail. You are only limited by your imagination.
29 XML
Imagine for a moment that you are tasked with the responsibility of
developing a new method of describing and housing data. This method
must be flexible enough to handle a great variety of data models, data
types, etc. It must be able to describe a car, a family of people, and a
farm. What would you come up with? Hopefully you would come up
with something like XML, because XML is designed to handle a variety
of data structures and types.
In this chapter:
[B What is XML?
[B XML file structure
[B Reading XML files with VBA
WHAT IS XML?
XML is an abbreviation for Extensible Markup Language. XML
documents often have a file extension of "xmI:' Even though XML files
conform to a common specification, the data they contain can vary
greatly from file to file and from structure to structure.
Companies and organizations create their own XML document
definitions to store their own type of data with their own data
585
586 I Chapter 29: XML I
structures. For example, there are XML documents to store financial
transactions, documents to store GIS information, and documents to
store architectural bills of material. XML formats have been devised to
store genealogy, sports statistics, and cooking recipes. Programs such as
Microsoft Excel and Microsoft Access can export their data to XML
files.
Available References: OK
~I,'I
i [J ~licrosoft XML, v2.6 Cancel
I[J Microsoft X~lL, v3.0
![J Microsoft X~lL, v4 .0
I[J Microsoft X~lL , vS.O Browse ...
I [J ~licrosoft X~lL, v6.0
IW I·licrosoft X~lL, version 2.0
I' !cd ~licrosoft. Vsa.dll
~
; U ~licrosoft_JScript .....,): Priority
![J ~licrosoft Vsa Help
I[J ~licrosoft - Vsa vb CodeDOMProcessor
! U ~limeDir I~O Tipe Library
I[J mmAEPlugIn 1.0 Type Library i
i [J ~lMC Internal Web Browser event sink 1.0 Type Librc .!
I 1"" 1, ~'11MFlltil 1 ..~. Tvnp. I .ihr~rv ..;·":!.·!1
! .~/ ..•. '''' .. .'. '... 1 ••.>..1 ,
w3ext 1.0 Type Library
Location : C:\WINDOWS\5ystem32\inetsrv\w3ext.dll
Language: Standard
Sub ReadXMLFi 1 e ()
Di m myX ML As New MSXML2.DOMDocument
Di m myXElem As MSXML2 . IXMLDOMElement
Di m myXRecord As MSXML2 . IXMLDOME l ement
Dim myXF i el d As MSXML2. IX MLDO MElemen t
588 I Chapter 29: XML I
myXML.async = False
myXML.va li dateOnParse = False
myXML.Load "c:\MicroStation VBA\parcel.xml "
Set myXElem = myXML.documentElement
For Each myXRecord In myXElem.childNodes
Debug.Print "****NEW RECORD****"
For Each myXField In myXRecord.childNodes
Debug.Print myXField.baseName &" "& myXField.Text
Next
Next
End Sub
This example loads the XML file and then prints each record with its
children (the fields) in the Immediate window.
~~~*NEW RECORD~***
mslink .. 1
old_map_no .. 119-L
gJ:oup_no .• A
paJ:cel_no •. 9
clt_no .. 119-LA 9
owneJ:. . CANTRELL hlILLIAM B & EVELYN hl
paJ:c_value .. 9000
house_mUll .• 220
stJ:_name .. BRIDGEhlATER RD
city .• KNOXVILLE
state .. TENNESSEE
zip_code .. 37919
county •• KNOX
distJ:ict . . NW-COUNTY
zone_class .. RA
block_num .. 0
lot_num . . 0
subd_name .. CRESThlOOD HILLS UNIT 1
paJ:c_aJ:ea .• 16036
peJ:imeteJ: .. 511
mapid .. 6
cUJ:J:date .. 1986-09-19TOO:OO:OO
txt .• This is a memo field, used fOJ: J:eally long text entJ:ies
The procedure ReadXMLFi 1e starts at the beginning of the file and looks
at each item until it reaches the end.
If you only want to display the record with a mslink of 531, you could
use the following code:
Sub ReadXMLFi l eB ()
Dim myXML As New MSXMLZ.DOMD oc ument
Dim myXElem As MSXMLZ.IXMLDOMElement
Dim myXRecord As MSXMLZ .IXMLDOMElem ent
Dim myXField As MSXMLZ.IXMLDOMElement
myXML . async = False
I Read ing XML Files I 589
Sub ReadXMLFileC ()
Dim myXML As New MSXML2.DOMDocument
Dim myX Elem As MSXML2 .I XMLDOMElement
Dim myXList As MSXML2.IXMLDOMNodeList
Dim myXRecord As MSXML2 . IXMLDOMElement
Dim myXField As MSXML2 .I XMLDOME leme nt
myXML . async = False
myXML.va l idat eOnPar s e = False
myXML . Load "c : \MicroStat i on VBA\parcel.xml "
Set myX Elem = myXML . documentElement
Set myXList = myXML . getElementsByTagName( "mslink " )
For Each myXReco rd In myX Lis t
I f myXRecord.Text = "53 1" Then
For Each myX Fi el d In myXReco rd . parent Node . ch il dNodes
Debug.Print myXFie l d. baseName & " .. " & myXFie l d.Text
Next
End I f
Nex t
End Sub
590 I Chapter 29: XML I
The code runs faster than the previous example but can be improved by
looking for the first node that has an mslink value of 531.
Sub ReadXMLFileD ()
Di m myX ML As New MSXML2 .D OMD ocument
Dim myXFie l d As MSXML 2.IXMLDOMElement
Dim myXNode As MSXML2.IXMLDOMN ode
myXML.asyn c = False
myX ML.validateOnPa r se = False
myXML.Load "c: \MicroStation VBA\parcel.xml"
Set myX Ele m = myXML .d ocume ntElement
Set myXNode = myXML.selectSingleNode("//parcel[mslink=531] " )
For Each myXF ield In myXNode .c hildN odes
Deb ug . Pr i nt myXF i eld . baseName & " " & myXField . Text
Next
End Sub
Now we are getting somewhere by letting the Microsoft XML Library do
the work. It is fast, efficient, and very easy to modify. Not matter how
deep the parcel object is in the XML file, this code finds the first
instance where the mslink property of the parcel object is equal to 531.
Looking at the screen capture shown previously, you will see a good
number of fields to work with. One is "parc_value:' You could modify
the code above, looking for "parc_value" instead of "mslink" and find a
parcel valued at 250,000. But the code only works if a parcel is valued at
exactly 250,000. Let's examine the code that will return all parcels (not
only one) with a value greater than or equal to $250,000.
Sub ReadXMLFileE ()
Dim myXML As New MSXML2.DOMDocument
Di m myXList As MSXML2.IXMLDOMNodeList
Dim myXField As MSXML2.IXMLDOMElement
Dim myXNode As MSXML2.IXMLDOMNode
myXML.async = False
myXML . validateOnParse = False
myXML.Load "c: \M icr oStat i on VBA\parcel.xml"
Set myXList - myX ML. selectNodes("/ l parcel[pdr·c_value>-250000] " )
Debug . Print myXList.Length & " Found ."
For Each myXNode In myXL i st
Debug . Print "*****PARCEL***** "
For Each myXF i eld In myXNode.childNode s
I Read ing XML Files I 591
81 FOWld ,
1; 1; 1; 1; 1; PARCEL 1;1; 1; 1; 1:
ms link, , 7
old_map_no , , 119
p ar cel_no, , 34
c l t _no , , 119 34
O1J1ler. ,CGS LAND COHPAlN
parc_value , ,675000
s tr_name " P 0 BOX 10845
city, ,KNOXVILLE
state, ,TENNESSEE
zip_code,, 3791 9
COWlty, , KNOX
district " Nhl-COUNTY
zone_clas s "CA
block_num, , 0
lo t_num, , 0
parc_area , ,4822 06
perimeter , , 3170
mapid, ,6
currdate,,1 99 8-09-11TOO:OO: OO
txt, ,This is a memo field, used for re al l y long text entries
The code is beginning to look a little like an SQL statement but it really
is an XPath statement.
A careful comparison between the screen capture shown here and one a
few pages ago shows that this one is missing the "group_no" field and
the "house_num" field, In a previous example, I used childNodes(O) to
get the "mslink" field. I addressed the "mslink" field by an index number
instead of its name. You can see here that some records do not have all
fields represented, so you should be extremely careful when addressing
fields (or nodes) by their index - it is far better to address a field by its
name.
This next example displays information about each record where the
parcel area is greater than or equal to 1 acre.
Sub ReadXMLFileF ()
Dim myXML As New MSXML2 , DOMDocument
Dim myXList As MSXM L2, IXMLDO MNodeL i st
Dim myXField As MSXML2 . IXMLDOME l ement
Dim myXNode As MSXML2 . IXMLDOMNode
myXML , async = False
myXML , validateOnParse = False
my XML. Loa d "c: \ Mi c r 0 Stat ion VBA\ par eel , xm1 "
592 I Chapter 29: XML I
Set myX Li st = myXML .s elect Nodes( "/lp a rcel [p arc _a rea) =43560 ]" 1
Debug . Pr i nt myX List . Length & " Parcels Found )= 1 Acre ."
For Each myXNode In myXList
Debug.Print myXNode.selectSingleNodeC".llmslink"l.Text & vbTab &_
myXNode . selectSingleNodeC " .llowner " l.Text & vbTab & _
myXNode . selectSing l eNode(".llparc_area " ).Text
Next
End Sub
In the above example, I use selectNodes to select multiple nodes
meeting the criteria specified. I then look at each node that is found and
get its "mslink;' "owner;' and "parc_area" values. Note that I use ",/1"
with a period (.) instead of "I/". When I use a period, I state that I want
to look relative to the current context. If I did not use the period in the
above example, it would find the first "mslink", "owner", and "parc_area"
nodes in the XML document.
Let's look at one more example of reading this Access-exported XML
document.
Sub ReadXMLFileG ()
Dim myXML As New MSXML2.DOMDocument
Dim myX Lis t As MSXML2.IXMLDOMNodeList
Dim myXField As MSXML2.IXMLDOMElement
Dim myXNode As MSXML2.IXMLDOMNode
myXML.async = Fal se
myXML.validateOnParse = False
myXML. Load "c: \M i croSta t ion VBA \pa rce 1 . xm l "
Set myXL i st - myXML.sele ctNodes( "ll parce l [parc_a rea ) -43 560 " &
"and parc_area<=87 120] " )
Debug.P ri nt myXL i st . Lengt h & " Parce l s Fou nd Be t ween 1 and 2 Acres. "
Fo r Eac h myX Node In myXList
Debug . Pr i nt myXNode . se l ectSing l eNode( " . ll msl i nk " ).Text &_
vbTab &
myXNode . selectS i ng l eNode ( ". l lowner " ) . Text &_
vbTab &
myXNode . selectS i ng l eNode( ". llparc_area " l.Text
Next
End Sub
I Reading XML Files I 593
Now I expanded the filter to only return nodes with "parc_area" values
between 1 and 2 acres. I again export the "mslink", "owner': and
"parc_area" node values to the Immediate window.
t:l~ Ella' ~t ' Il!elii ~ .!ns';,r( FQ,I'~t lo~ls ~ Qat~ l'lindow' tlelp ,Ado!le PDF "
r~J;);id"\~$.;(t.:s.:.:.~~<m *_ "'""-<"" ,~.. .. ,~,,,,, ""', ~k~ ... ~, . <.U( ~ * ,,~. $, _ ~ .ZO
I~ 0 lC3 ~ G; t91 (§} ~I ,:" ~ I ~ ~ ,lJ!b . ::/ I "1 · ('1 .I.@, 1: • ,~~~J L~ ~l} , 100%
rU~ ~~ p 4.~ 4~J" ,,", ~ '" ! , " , "rm'?
02
1
2 -- -,,'table Tension! 1200 l,7ico,lor
3 "r Y":Eij ghtjft; , 2 13 towers
4 TtN' ~OO ,_ '
5
6 I-::-::-=:Yc'-I_ _ _~zJ..::1O""A'T7-=-:A:":SE,=,T,==-=,,I_ _Co..;ac::b-:o:
"I-I--.-::c=-:'::x:,,- 1e""x+-IC""a:::-::b:-::
le::-:Y""p""a""bl::,:e:'7Z1
7 18325 22791 514 , xy= 1 8~25,2279 18290 ' 22929 894
8 18414 22609526xy~ l B414,??60 18379 22747 906
9 18427 222242' 47"'6~' 465 ,xy~ 1 ~42?,22~4; 18392 22582 845
10 184414}§~/=lB441,?227 18406 22414 816
11 18461 22062 446:>y=184§1,?206, " 18426 22200 826
12 18458 21940 420xy~ 1 8~5~,2 1 94 184?} 22078 800
13 18492 21852 343 X'>,=18492.2185 , 1~1??.. } 1~90 (23
14 18446 21835 335 ' xy~184;;ilf2 ; 83 -- 1841 1 21,973 715
15 18653 21454 4~6~/=18653.21~5 1861~ 21592 ,,, 816
16 18610 21374 361 xy=18610.2137 18575 2151 2 741
17 18495 21363 259 xy~184 95,2136" 18460 21501 639
18 18485 21198 224 xy=18485.2119 18450 21336 604
594 I Chapter 29: XM L I
The "towerdat.xls" spreadsheet is installed with MicroStation. When
exported as a "Spreadsheet XML" document, you can traverse the data
using the Microsoft XML Reference.
Sub ReadXMLFilel()
Dim myXML As New MSXML2 . DOMDocument
Dim myWSheets As MSXML2.IXMLDOMNodeList
Dim myWSheet As MSXML2.IXMLDOMNode
Dim myRows As MSXML2.IXMLDOMNodeList
Dim myRow As MSXML2 . IXMLDOM Node
Dim myCe l ls As MSXML2 .I XMLDOM NodeL i st
Di m myCell As MSXM L2 . I XMLDOMNode
my XML. async = Fals e
myXML . validateOnParse = False
myXM L. Load "c : \MicroS t at i on VBA\towe r dat . xml "
Sub ReadXMLFile2 ()
Dim myXML As New MSXML2.DOMDocument
596 I Chapter 29: XML I
Dim my WSheets As MSXML2. I XML DOMNode Lis t
Dim my WSheet As MSXML2 . IXMLDOMNode
Dim myRows As MSXML2.IXM LDOMN odeList
Dim myRow As MSXML2.IXMLDOMNode
Dim myCells As MSXML2.IXMLDOMNodeList
Dim myCell As MSXML2.IXMLDOMNode
Dim myRowAtt As MSXML2. IXMLDOMAttribute
Dim myColAtt As MSXML2.IXMLDOMAttribute
Dim myAtts As MSXML2.IXMLDOMNamedNodeMap
Dim CurRow As Long
Dim CurCol As Long
myXM L.async = False
myXML . validateOnParse = Fa l se
myXML . Load "c:\MicroStation VBA\towe rdat . xml "
CurCol = 1
Set myCells = myRow.selectNodes( " .IICell " )
For Ea c h my Cell I n my Cell s
Set my At t s = my Cell . Att r i bute s
Set myColAtt = myAtts.getNamedItem("ss:Index " )
If Not myColAtt Is Nothing Then
CurCol myColAtt . Text
Else
CurCol = CurCol + 1
End If
Debug.Print " R" & CurRaw & " C" & CurCal & "=" & myCell . Text
Next
I Review I 597
Next
Next
End Sub
R2C2=
R2C3=
R2C4=Cable Tension
R2C6 =1 200
R2C7=
R2C8=17
R2C9=color
R3C3=
R3 C4=weight/ ft
Here is the output of Rea dXM LFi 1e2 . Notice that some of the cells have an
empty string ("") for their text property.
REVI EW
XML is a technology that has been talked about for years and is
becoming used more widely. The ability to read XML files is not only
useful now but will become more critical in the days to come.
Since each xml Document Definition varies, you may need a little time
to learn how to traverse a new XML file type.
598 I Chapter 29: XML I
30 Batch Processing
The ability to rapidly process 10, 100, or even 1000 files is as simple as it
is powerful.
In this chapter:
[B Processing files listed in an ASCII file
[B Processing all files in a folder
[B Processing all files in a folder and subfolders
[B Creating a user interface for file selection
[B Logging batch file processing
599
600 I Chapter 30: Batch Processin g I
This first example opens the file ProcessThese.txt, reads each line in it,
then displays each line in a MessageBox.
Sub ProcessASCII()
Dim FileToOpen As String
Dim BatchFile As String
Dim FFile As Long
FFile = FreeFile
BatchFile = "C:\MicroStation VBA\BatchProcessing\ProcessThese.txt"
Open BatchFile For Input As #FFile
While EOF( FF ile ) = Fa l se
Lin e In put #FF i l e, Fi leTo Op en
MsgBox Fi leToOpen
Wend
End Sub
Sub ProcessASCIIB ()
Dim FileToOpen As String
Dim Batc hFile As String
Dim FFi le As Long
FFile = FreeFile
Ba t chFi l e = "C: \M i croStat i on VBA\BatchP r ocess i ng\ Pr ocessT hese . txt"
Open Bat chFi le For Inp ut As # FFi l e
Wh i le EOF(FFi l e) = False
Li ne Inp ut #FFile, Fil eToOp en
Appli ca t i on.O pen Desig nFil e Fi l eToOp en , Tru e
Msg Box "Do Som eth i ng"
We nd
End Su b
Instead of just showing the file name in a MessageBox, we open each file
in MicroStation with the "Read Only" parameter set to True. This is
useful when you need to extract information from files but don't want to
make any changes to the file. Note that we only open the files, we do not
close them.
I Processing Fi les Listed in an ASCII File I 601
Let's change the ASCII file format. After the path and name of the file,
we have lines specifying which levels to process. Each level line in the
file should begin with a tab and then have the level name. After adding
level names to the file, we perform a SaveAs to the file with a new
filename of ProcessTheseLevels.txt.
" '-""" ~" '.- , ....~ . -~: .,~, "' ...
:' """ . :-4<~,~~'t' '<" ~;H'7>.3~~;"'" ''Y'''''~ f'' ,'" ""'-- .""
Here instead of opening each file and displaying the file name in a
MessageBox, we open each file and display each level name in a
MessageBox.
Sub ProcessASCIIC c)
Di m Fil eToOpen As St r in g
Dim Batch Fi l e As St ri ng
Dim st rL IN As Stri ng
Dim FF il e As Lo ng
FFi l e = Fr ee Fi le
BatchF il e =
"C: \ MicroS tation VBA\BatchProcessing\ProcessTheseLevels . txt"
Open BatchFile For Input As #FFile
While EOFC FFile) = False
Line Input #FFile. strLIN
Select Case LeftCstrLIN. 1)
Case vbTab
MsgBox "Do something to Level " &
ReplaceCstrLIN. vbTab. "H)
Case El se
FileToOpen = strLIN
Application.OpenDesignFile FileToOpen . True
End Select
Wend
End Sub
602 I Chapter 30: Batch Processing I
The procedure Pr ocessASC I IC works very well if the specified files exist.
What happens if you attempt to open a file that does not exist?
<_ T " . _ . ~ • ",,-
~ Informatjon
Prior to attempting to open any file, make sure the file exists.
Sub ProcessASCIIO ()
Dim Fi l eToOpen As St r in g
Dim BatchFile As String
Dim strLIN As String
Dim FFile As Long
Dim Fil e IsOpen As Boolean
FFile = FreeFile
BatchFile =
"C: \ MicroStati on VBA\BatchProcessing\ProcessTheseLevels.txt "
Open BatchFile For Input As #FFile
While EOF(FFile) = False
Line Input #FFile. strLIN
Select Case Left(strLIN. 1)
Case vbTab
If FileIsOpen = True Then
MsgBox "Do something to Level " &
Replace(strLIN. vbTab. "H )
End If
Case Else
FileToOpen = strLIN
If Di r(F il eToOpen) "" Then
FileIsOpen False
Else
FileIsOpen = True
ApplicQtion.OpenDesignFilc FilcToOpen. True
End If
End Select
Wend
End Sub
I Processing All Files in a Folder I 603
Sub ProcesslnFolderA()
Dim myFSO As New Scripting.FileSystemObject
Dim myFolder As Scripting. Folder
Dim myFile As Scripting.File
Dim RootFolder As String
RootFolder = "C:\MicroStation VBA\BatchProcessing"
Set myFolder = myFSO.GetFolder(RootFolder)
For Each myFile In myFolder.Files
Select Case UCase(myFile.Type)
Case "BENTLEY MICROSTATION DESIGN FILE"
Debug.Print myFile.Path
End Select
Next
End Sub
604 I Chapter 30: Batch Processing I
Each file in the RootFo lder is examined. In this example we look at the
type of file. The file type is associated with the file extension. You can see
the file type by looking at files using Windows Explorer. Another way to
find design files is to look at the file extension.
Sub ProcesslnFolderB()
Dim myFSO As New Scripting.FileSystemObject
Dim myFolder As Scripting. Folder
Dim myFile As Scripting.File
Di m RootFolde r As Str i ng
RootFolder = "C:\MicroStation VBA\BatchProcessing "
Set myFo l der = myFSO.GetFolder(RootFolder)
For Each myF i le I n myFolder.Fi l es
Sel ect Ca se UCase(R i ght(my Fi le.Name , 3))
Case "D GN "
Deb ug .Prin t my Fil e . Pat h
En d Se l ect
Next
End Sub
Instead of looking at the type, we look at the last three letters in the file
name. If we find a DGN file, we know we are looking at a MicroStation
design file and we print it to the Immediate (Debug) window.
We are off to a good start. Instead of printing the path of each DGN file
in the RootFo lder to the Debug window, we should open the file in
MicroStation and 'Process' it. The procedure Proc ess lnFold erB works
well as long as the files we want to process are in the folder
C:\MicroStation VBA\BatchProcessing. Of course, we wouldn't want to
change our code every time we need to process files in a different folder,
now would we?
Sub ProcesslnFolderC ()
Dim myFSO As New Scr i pti ng.F i leSystemObject
Di m myFolde r As Scripting . Folder
Dim myFi l e As Scripting .F ile
Dim RootFolder As String
RootFolder = InputBox( "Enter Root Folder: " )
Set myFo l der = myFSO.GetFolder(RootFolder)
For Ea c h my Fi 1e I n my Fol de r . Fi 1e s
Select Case UCase(Right(myFile.Name, 3))
I Processing All Files in a Folder I 605
Su b PickAFolder ()
Di m myS hell As New Shel132 . She l l
Dim myRootFolder As She l 132 .Folder3
Set myRootFolder = myShell.BrowseForFolder(O, "Pick ", 0)
MsgBox myRoo t Folder.Self.Path
End Sub
Pick
8 !b ~licrostation VBA A ,
[3 B j:I!iMi.f241hGi
[310 BatchA
a BatchA·\
Ii:;) BatchA-2
a BatchA-3
10 BatchB
Ii:;) BatchC
!b BatchD
i±l !b cd material
Ii:;) docs
Ii:::! Fonts V '
Sub ProcesslnFolderE ()
Dim myFSO As New Scripting.FileSystemObject
Dim myFolder As Scripting . Folder
Dim myShel l As New Shel132.Shell
Dim myRootFolder As Shel132.Fo l der3
I Processing All Files in a Folder and SubFolders I 607
Set myRootFol der = myShell . BrowseF orF ol der (0, "Pi ck " , 0)
Set my Folder = my FSO .Get Folder(myRootFolder .S elf . Path)
Process Fi l esAndSubs my Folde r
End Sub
have been selected for batch processing. We want the user to be able to
choose which folder to select from. We will use buttons to move
"Selected" or "All" files from one ListBox to the other. We will also allow
the user to double-click a file to move it from one ListBox to the other.
GO
lstFileslnFolder.Addltem myFile.Path
610 I Chapter 30: Batch Processing I
End If
End Select
Next
End Sub
GO
A few items worthy of mention that may not be apparent at first glance:
[B We set the MultiSelect property of the ListBoxes to 'Extended'
so more than one item can be selected and the user can use the
<Control> and <Shift> keys to aid in the selection of items in
the list.
[B To simplify the design process and reduce the potential for
bugs, only one procedure, "MoveSelection" is used to move
items from one ListBox to the other. Each of the buttons calls
this same procedure, even the double-click events of the
ListBoxes
[B Clicking the GO button simply prints the files in the Process
ListBox to the Immediate window. The reader can insert
whatever code will process the files.
[B Although not in this project, the addition of a few lines of code
allows the user to select a CheckBox specifying to "Search Sub-
Folders" as well as the selected folder.
[B The "Current Folder" TextBox is locked. This allows the user to
select and copy the path from the TextBox to the Windows
Clipboard but the user cannot type into the TextBox. This is
I Logging File Batch Processing I 613
the .mvba file has been saved, it has an actual path. If we can find that
path, we can write a .log file to the path and we can easily find it.
Sub TestLogFile ()
Writ eT oLo g "Op enin g C:\ te st.d gn "
En d Sub
Sub TestLogFileB( )
Writ eToLogB "Ope ni ng C: \test . dgn "
End Sub
Sub WriteToRegistry()
SaveSetting "MicroStation VBA", "Batch Processing", _
"LastFile", "C:\FileA.dgn"
SaveSetting "MicroStation VBA" , "Batch Processing", _
"CurrentF i le", "C: \FileB.dgn"
End Sub
~I
Sub ReadFromRegistry()
Dim Las t File As String
Dim CurrentFile As Stri ng
LastFile = GetSetting("MicroStation VBA", _
"Batch Process i ng", "LastFi l e" )
CurrentFile = GetSett i ng("MicroStation VBA " , _
"Batch Pr ocess i ng " , "Cur r ent File " )
Debug.Pr i nt Last File
De bug .P ri nt Curre nt Fi l e
End Sub
http://www.google.com/search?q=MicroStation
Google returns thousands upon thousands of pages related to
MicroStation.
I Logging File Batch Processing I 617
Sub LogToWeb ()
Dim LocalFile As String
Di m myInet As New Inter net Explorer
Loca l File = "filea.dwg"
myInet.Nav i ga t e _
.. ht tp: //www.microstationlogging . com?f il ename= . &
Loca lF i 1e
While my In et .Bu sy
DoEvents
Wend
End Sub
The code consists of only a few lines. LogToWeb navigates to the specified
URL, in this case, the fictitious website, www.microstationlogging.com.
If this were a real website, and if the default page at that web site received
the parameter "filename", it could log the file name sent to it into a
database on the web server.
Logging information to the Web has its advantages. For one, it doesn't
matter where in the world the individual who is running the program is.
If the computer is connected to the Internet, it can have its activities
logged. Web servers are specifically designed for high traffic, high
volume situations so we could have hundreds or even thousands of
people using this site to log their activities without causing any
problems. Others may hit the site to see real-time statistics as to what is
happening, who is working and who isn't, average time per file, etc. The
sky's the limit. And it is all possible by making a simple reference in VBA
and then navigating to a specific URL.
This same technique can be used to get information from a website.
Although this is not a chapter on Internet technologies, a small example
won't hurt.
618 I Chapter 30: Batch Processing I
The Bentley Institute sponsors VBA training from time to time. We can
find training dates, locations, and costs on th eir web site. This macro is
designed to display this information in a MessageB ox.
As the time of this writing, three classes are scheduled. Their dates,
costs, and locations are shown here in this MessageBox. The code is
designed to find specific HTML tags and annotation to drill down to the
information we want. The HTML for this page may change in the future,
but this shows how easy it is to create our own information gathering
tools using VBA.
Available References:
C2GJ
r~icrosoft APC 6.0 Object Librar y
~licrosoft APC 6.3 Object Library
~
Microsoft APC 6.4 Object Library
Microsoft AutoDiscovery Type Librar y Browse .. .
Priority
Help
If the reference does not show up in the list, clicking the Browse button
and browsing to C:\ Windows \sys tem32\Cdosys. dll does the trick.
620 I Chapter 30: Batch Processing I
CDO. What does it stand for? Collaborative Data Obj ects. In plain
English, e-mail.
Sub TestEmail ()
Dim myMail As New CDO.Message
myMail.To = "batch@microstationlogging.com"
myMail.From = " batch@microstationlogging . com"
myMail.Subject = " MicroStation VBA Batch Process Log"
myMail.HTMLBody = "<b>File name: filea.dgn</b><br>" &
"Computer: " & ThisComputerName & "<br>" &
" Date : 1/1/2005 "
myMail . Configuration.Fields . ltem( '' http : //schemas . microsoft . c om/" & _
" cdo/con fi guration/sendus i ng " ) = 2
myM ai l.Co nfigu rat i on.Fi e l ds .It em( '' htt p : // s chemas . mic r osoft . co m/ '' & _
" cdo/config uration/smtpserver " )
"yoursmtpserver . com "
myMa i 1 . Con fig u rat i on. Fie 1 d s . Item ( " http : I I schema s . mi c r 0 soft. c om I " &
"cdo/configuration/smtpserverport " ) = 25
myMai l .Configura t ion . Fields. Update
myMa i 1 . Send
End Su b
That's about as difficult as it gets. With the right reference and a little bit
of code, our program is now capable of e- mailing batch processing
information to an e-mail address. In order for this code to work
correctly, the "To" property should be set to a legitimate e-mail address
and the SMTPServer Field should be set to a legitimate SMTP server.
And how difficult is it to attach a file to this e-mail?
Sub TestEmai 12 ()
Di m myMail As New CDO . Message
myMail.To = " batch@microstationlogg i ng . com "
my Mai l . From = "b atc h@mi c r ostat i onlogging.com "
myMail . Subject = " Mi croStat i on VBA Batch Process Log "
myMa i 1 . HTMLBody = " <b>F i 1 e name : f i 1 ea. dgn</b><br> " &
" Computer: " & ThisComputerName & " <br>" &
" Date: 111/2005 "
myMail .Configuration.Fields . ltem( '' http : //schemas.microsoft.c om/" &_
" cdo/configuration/sendus i ng " ) = 2
my Mail . Con fig u rat ion . Fie 1d s . I t em ( " http : I I s c hem as . mi c r 0 soft . com I " & _
"cdo/configuration/smtpserver " ) = _
I Review I 621
REVIEW
The task of batch processing is accomplished relatively easily. We need
to know which files to process. This can be discovered by using an
ASCII file, having the user select a folder to process, or selecting
individual files within a folder. Next, we need to process the files . Along
the way, we can log our activities through a variety of methods.
Once our code is in place, it matters very little whether we need to
process 5 files or 5,000 files. Our productivity and accuracy can increase
exponentially compared to manually opening each file one by one.
622 I Chapter 30: Batch Processing I
31 The Standards Checker
The Standards Checker helps keep our files in line with established
standards. Using this functionality as it is installed with MicroStation
can do a fairly good job performing basic standards checking - add the
power and flexibility of VBA and nothing can hold us down.
First, you should note that unhandled errors that occur in your
standards checker routines can cause severe errors. Some may even shut
down MicroStation completely. So, you need to take care when working
with standards checker code. Make sure to save your VBA Projects often
and verify that any DGN files open in MicroStation are also saved.
In this chapter:
[8 Basics of implementing the standards checker
623
624 I Chapter 31: The Standards Checker I
End Sub
End Property
End Sub
End Sub
End Property
End Property
I Basics of Implementing the Standards Checker I 625
En d Property
End Sub
End Property
End Property
End Sub
End Property
Six events and seven properties are implemented. As the user begins the
Standards Checker by selecting Utilities> Standards Checker> Check,
the properties in our class module are used in the standards checker
user interface. Let's implement a standards checker that does nothing
626 I Chapter 31: The Standards Checker I
other than implement the most basic properties and uses Debug.Print
statements so we can see the order in which events take place.
Standards Check A
The following code is placed in a class module named
clsStandCheckA.
Option Explicit
Implements IStandardsChecker
Option Explicit
Private StandChk As clsStandCheckA
Sub AddChecker( )
628 I Chapter 31: The Standards Checker I
RemoveChe c ker
Set Stan dChk = New cl sStandC heckA
StandardsCheckerController.AddStandardsChecker StandChk. 1000
End Sub
Sub Re moveChec ke r ()
If Not StandChk Is Nothing Then
StandardsCheckerController.RemoveSta ndar dsChecker StandChk
End I f
Set Stan dChk = Nothing
End Sub
When we run AddChe cker, the class module is instantiated and added to
MicroStation's Standard Checker dialog box.
"'i1:?f~'t::;""~~"0~"~"r"--'~n7'¥~-::"T: P'Cr ~~-·v~y;':~'}~ ; <v.~ , "'I; ,~~ ~~ ':- .,,'" <... ~"',.~ ~'? /'",:,,"\_j~ ';.v
~t~!,.d!llJ!~(:hec~J" S~~!I!]gs" .";:;,,, ".•.• J »",>,> > >,>,'• • > ,.. A>< "> i
Settings -·--·•.- · - - -: : - - · - -- - - -- - - - -·- -
:$~tii6d.~H~~:~ IW:OOld¥WP;;W;
Checks -'----------,,-,-----'---~.---
.CilVBA, StandChk A Dial
~heck Levels
D Check Text St~les
D Check Dimension Styles
D Check Element Templates
o Check Line Styles
D
.C " !] Cancel
When we run the standards checker, we can see how the properties
returned in the class module are used. In this view we can see "VBA
StandChk A Dial" which comes from the Di a1ogS tri ng property. Prior
to creating the class module, the "VBA Check ~' setting in the
Standards Checker Settings Configuration dialog box was created.
We can select the "VBA StandChk A Dial" CheckBox and can click the
settings button. When we do so, events are triggered and their
associated Debug.Print statements are executed.
At this point we are able to get our own standards checker into the
Standards Checker dialog. A good start. But nothing to write home
about. Before we continue let's talk about the entire standards checker
process.
I Basics of Implementing the Standards Checker I 629
~tii!Jdards Ch!!cke~ Setti,llg!!" '<, " ' \ '" ,,.:, , ,," :',,'
Settings ----,----,-
i~~ii;:69S.H~~~ I~W:~
r!1~Il;n~*~~.~• •~,v~a DX
Checks - - - - - - - , - - - - - - - - - - - - - -----,-
D Check Levels
OK Cancel
630 I Cha pter 31: The Standards Checker I
If, however, the HasSettings property returns a value of False, we do
not get a Settings button and the standards checker we created is
enabled and ready to be selected.
1· ,,~~'I' ~ ~ ~ - ~ -
:$:~~:;69iHi1.m:~ m Check.1>. vi ~j x
Checks ~-----~-----------
Cancel I
UserForml . Show
End Su b
Of course, the Debug.Print statements are only here to help us see the
order in which the events are triggered. The important things are to set
the IStandardsCheckecHasSettings to True and to display a UserForm
in the EditSettings event. At this point, we are ignoring the IsReadOnly
parameter of the EditSettings event.
So, what settings are we going to allow the user to set? By default,
MicroStation has settings for levels, text styles, dimension styles,
element templates, and line styles. What else is there to check?
P' [~9.9.~L.~~~ji.i/Yii~~~~:j~~ii~!
r File Contains Only l egitimate Room l abels
chkCleanF il e .Valu e =
GetSetting("VBA Standards Checker ", "Settings " , "Clea n File " , False)
chkF i xErrors.Value =
GetSetting( "VBA Standards Checker ", "Settings", "Fix Errors ", False)
GetSetting( "VBA Standards Checker ". "Settings ", "File Path ", _
"C: \MicroStation VBA\Labels.txt " )
I Standards Checker Settings I 633
En d Sub
SaveSetting " VBA Standards Checker " , " Sett i ngs ", _
" Labels Written ", chk LabelsWritten . Value
SaveSetting " VBA Standards Checker " , " Sett i ngs " , _
" File Path ", txtF i lePath . Text
Unload Me
End Sub
[8 Check to make sure labels in the file have tags in the DGN file
' *********
If UBound (myTags) )= 1 Then
ReDim Preserve my Tags(UBound(myTags) - 1)
End If
End Sub
The procedure is rather lengthy, so let's discuss each segment.
638 I Chapter 31: The Standa rds Checker I
1 Declare variables.
This section is self-explanatory. We use a couple of dynamic arrays
because before the code is executed, we do not know how many room
labels we will find in the drawing or in the file.
2 Read all room label tags in drawing.
We create a ScanCriteria filtering on tags. We then look to see which
tags in th e drawing are "Room Lab els". When we find one, we assign it to
the last element in the dynamic array myTags and then increase the size
of the array, preserving the existing values.
3 Get settings from registry.
Placing the standards checker settings into variables means we only
need to read them once and our code is easier to read than having
multiple GetS et t i ng calls for the same Registry entry.
4 Read room label file.
We specify a file name in the Settings dialog box. This file is to contain
all room label values in our DGN file. If the file exists, we read the file,
placing each line of the file into its own element in a dynamic array.
S Check for file's existence.
If the file in which we are placing room label values does not exist, we
create it and populate it if the "Automatically Fix Errors" setting is True.
6 Check for tags in file.
We look at each room label tag found in the drawing file and check for
its presence in the file. If the room label tag is not found in the file, we
add it to the file (if AutoFix is True) and report the error to the Debug
(Immediate) window.
7 Check to make sure labels in the file have tags in the DGN file.
lt is possible that the ASCII file we are looking at has room label values
in it that are not in the drawing. This could be due to data entry errors
or the result of having deleted a room label from the drawing. In either
case, if we find a room label in the ASCII file that does not have an
associated room label value in the drawing, we report the problem by
printing to the Immediate window.
I Standards Checker Reporting I 639
Next
End I f
End If
End Sub
So, we have added a few lines of code. What does this get us?
• ~ • ~.' _ , .... ,.... " • ...., ' -.. ,,~ >-c' .... ,._v ....'" _~ ~ "~"
~~ ' , ' . . .' .: BenUey Systems, Inc. Siandards Cl1ecker "-",' '.,
. Version 8.9.2,12 ' !;.
StandardsChecked:
And if we expand the listing below the file name we see the specific
problems we added above.
11 Bentley Systems, Inc. Standard. Checker ~@~
fde Edit VIew Favorites Tools Help
Files Processed : DExpand All ~ Hide Ignored Problems o Hide Fixed Problems
. last nate Problems
File Nome Sile Form.t Author Modified Checked Remaining Ignore
, C:lOocument •• nd SettingslAll U.erslApplicatlon . . 2006103117 20D6f03124
.0 O.t"Bentley\WorkSp.ce\ProJect.\Ex.mples\BulldlngI OgnIBSI3DOAE101· 350kb OGNV8 Admln15trotor 23'45'22 14'00'52
PI.n.dgn .. ..
64 0
Case ErrorType.NotlnFile
mySCC,TotalProb l ems = mySCC.TotalProblems + 1
Set myProb = myRep.AddProblem( "Room " & RoomNumber &
" is NOT in file, ", "VBA CheckA ", False )
Case ErrorType.FixedNotlnDGN
mySCC,Fi xedP ro blems = mySCC.Fi xe dP ro blems + 1
646 I Chapter 31: The Standards Checker I
Set myProb = myRep.AddProb l emC"Roo m .. & Roo mNum ber &
.. is NOT in DGN . ... "VBA CheckA". True)
Case ErrorType.FixedNotlnFile
mySCC . FixedProblems = mySCC . FixedProblems + 1
Set myProb = myRep.AddProblemC"Room .. & RoomNumber &
.. is NOT in file .... "VBA CheckA". True)
End Select
End Sub
Now, in addition to adding a problem to the report stating that the
problem was not fixed (the False parameter in AddProblem), we also
add Fixed Problems and Ignored Problems.
Here is the report now:
Now, in addition to seeing problems that have not been fixed, we see
problems that have been fixed and those that have been ignored.
I Automatically Load ing Custom Standa rds Checker Add-Ins I 647
Sub OnProjectLoad ()
AddChecker
End Sub
So, the OnP rojec tL oad procedure is the same for both autoload
mechanisms. What are the two mechanisms?
1 The first is selecting "Auto-Load" in the VBA Project Manager:
REVIEW
The Standards Checker interface provides the ability to create our own
custom standards checking programming. The MicroStation VBA
documentation includes additional examples of how to further
implement the IStandardsChecker interface.
32 Using the Windows API
In this chapter:
[B Declaring API calls
[B Declaring types
649
650 I Chapter 32: Using the Windows APII
Public Declare Function Beep Lib "kerne132 " (ByVal dwFreq As Long. _
ByVal dwDurat i on As Long ) As Long
The function name in the above declaration is "Beep:' It is an amazing
API call that beeps. It beeps as long and as high (or as low) as we ask it
to. You find API functions and procedures inside DLL (Dynamic Link
Library) files. This one is inside the kernel32.dll file. Let's try it out, shall
we?
After declaring the Beep function in the General Declarations area of a
code module, we can use it as follows:
Sub TestBeep ()
Beep 4000. 250
Beep 2000. 250
Beep 1000 . 250
Beep 500. 250
End Sub
Four beeps are heard, each lasting 114 of a second (250 milliseconds) at
different frequencies. The higher the frequency, the higher the beep.
Each beep is half the frequency of the previous frequency. This results in
four notes, each one octave lower than the previous.
The Beep API function is not the most useful API function known to
man, but for the moment, we are focusing on how to declare the
functions. We will see plenty of examples utilizing more powerful and
more useful API functions later.
Many Windows API calls are declared as functions. This means they
return a value. Oftentimes, the value they return tells us whether the
API call worked or if an error was encountered.
In addition to specifying the function's name, location (which DLL file it
appears in), and the parameters, Windows API calls often have an alias.
The alias is important when declaring an API function but we do not
use it in our code - we use the function or procedure name.
DECLARING TYPES
Some Windows API calls use types. A type is similar to an object in that
it has specific properties or members. Often, we declare a variable as one
of these types and then set some of its properties. After the properties
are set, we may use it as a parameter in an API call.
I Utilizing API Ca ll s I 651
Declare API types in the General Declarations area just like API
functions.
Sub TestSystemInfo ()
Dim mySystemInfo As SYSTEM_INFO
GetSystemInf o my Sy stemInf o
MsgBox my Sy stem In fo. dwNumberOf Proce ssors & " Processors ."
End Sub
You will see examples of more types declared as we look at more API
examples.
GetLogicalDrives
Public Declare Function GetLogica l DriveStr i ngs Lib "kerne132 "
Alias "GetLogicalDriveStringsA" _
(ByVal nBufferLength As Long, _
ByVal lpBuffer As String) As Long
GetDriveType
We can use GetLogi ca 1Dri veStr i ngs to get the drive letters on our
system, but how do we know what type of drives they are? Hard Drive?
CD-ROM Drive? Floppy Drive? We can use Get Dri veType . This example
also uses GetLogi ca 1Dr i veStr i ngs .
Sub TestDriveType C)
Dim DriveLetters As String
Dim xSplit As Variant
Dim I As Long
DriveLetters = Space(255)
GetLogicalDriveStrings LenCDriveLetters). DriveLetters
xSplit = SplitCDriveLetters. ChrCO))
For I = LBoundCxSplit) To UBoundCxSplit) - 2
Debug . Pr i nt "Drive " & xSplitCI) & " is a " &
ReturnDriveTypeCCStrCxSplitCI)))
Next
End Sub
>;
654 I Chapter 32: Using the Windows APII
This computer has a hard Drive (C), a CD/DVD Drive (D), a removable
Drive (E) which happ ens to be a Flash drive, and a mapped drive (Z).
GetComputerName
Public Declare Function GetComputerName Lib "kerne132"
Alias "GetComputerNa meA " (SyVal l pS uffer As String,
nSize As Long) As Long
Sub TestGetComputerName ()
Dim CompName As String
CompName = Space(255)
GetComputerName CompName, Len(CompName)
CompName = Left(CompName, InStr(l, CompName, Chr(O)) - 1)
MsgB ox CompName
End Sub
Knowing the name of the computer on which our code is running is a
useful piece of information. Once again, we use a buffered string. We
look for the null character Chr(O) and get everything to the left of it.
GetVersionEx
What operating system is the computer running? We need only ask
GetVersionEx to find out.
Sub TestOSVersion ()
Dim myVerlnfo As OSVERSIONINFO
Dim strSer vi ceP ack As St rin g
myVerlnfo.dwOSVersionlnfoSize = 148
GetVersionEx myVerlnfo
Select Case myVerlnfo . dwPlatformld
Case VER_PLATFORM_WI N32 _WINDOWS
Select Case myVe r ln f o . dwMi norVe r sion
Case 0
MsgBox "Wi ndows 95 "
Case 10
MsgBox "Wind ows 98 "
Case 90
MsgBox "W indows ME"
End Select
Case VER_PLATFORM_WIN32_NT
Select Case myVerlnfo . dwMajorVersion
Case Is <= 4
MsgBox "Windows NT Build " &
myVerInfo.dwBuildNumber
Case 5
Select Case myVerInfo.dwMinorVersion
Case 1
strServicePack = myVerInfo . szCSDVersion
strServicePack = Left(strServ icePack . _
InStr(l. strServicePack. Chr(O)) - 1)
MsgBox "Windows XP Build" & _
myVerInfo.dwBuildNumber & vbCr &_
strServicePack
Case 2
MsgBox "Windows .NET Server Build " &
myVerInfo.dwBuildNumber
Case Else
MsgBox "Windows 2000 Build " &
myVerInfo.dwBuildNumber
End Select
End Select
End Se l ect
End Sub
A MessageBox displays the operating system and in some cases the build
Windows XP Build 2600 number and service pack.
Service Pack 2
656 I Chapter 32: Using the Windows APII
Sleep
At times, we need to temporarily pause program execution. The Sleep
func tion allows us to specify how many milliseconds to sleep.
FindExecutable
The same .pdf file may be opened with Adobe Acrobat Reader 7 on one
computer and Adobe Acrobat 6 on another computer. Which program
is registered to open a .pdf file? Which program is registered to open
a .jpg file? Fi ndExecutab 1e tells us the path to the program that is
registered to open a particular file type.
Sub TestFindExecutable()
Dim strFileName As String
Dim strDirName As String
Dim strExeFile As String
strFileName = "eula . pdf "
strDirName = "C: \ Program File s\ Bentley \ Micr oStatio n"
s t r ExeF il e = Spac e( 255)
FindExecutable strFileName , strDirName , strExeFile
I Utilizing API Calls I 657
GetDiskFreeSpace
GetDiskFreeSpace gives us information about the provided disk name.
GetSystemMetrics
Knowing information about the computer on which our code is running
is very helpful. We can use GetSystemMetrics to return a wealth of
information.
GetTickCount
How long has it been since the computer was started? GetTickCount
answers this question in milliseconds.
Sub TestTickCount ()
4458484
4460484 Dim StartTicks As Long
Dim EndTick s As Long
OK ~
StartTicks = GetTickCount
660 I Chapter 32: Using the Windows APII
Sl eep 2000
EndTicks = GetTickCount
MsgBox StartTicks & vbCr & EndTicks
End Sub
GetUserName
Who is logged onto the computer?
Sub TestUserName()
Dim UserName As String
Di m xSp lit As Var i ant
User Name = Space(255)
GetUserName UserName. Len ( UserName)
xSplit = Sp l it(UserName . Chr(O))
User Name = xSp l it(O)
MsgBox UserName
End Sub
Get User Name is useful for logging who is performing what function. If we
get the ComputerName as well, we will know who, where, what, and we
can know when by using the Now function. As for the question "Why?"
Microsoft is still working on that API call.
NOTE: The MicroStation application object has its own UserName
property so we don't need this API call if we are using MicroStation
VEA.
GetWindowsDirectory
Where is Windows Installed? C:\Winnt? C:\Windows?
GetWindowsDirectory tells us.
Sub TestWindowsDir()
Dim WindowsDir As String
I Utilizing API Ca lls I 661
LogonUser
Security is on everyone's mind. How do I know that changes being made
on someone's machine are being made by the person that is logged on?
How do I know someone else didn't slide into Fred's cubicle while Fred
is at lunch only to goof up a file?
We know how to get the current user. Let's take a look at how we can ask
the user for a password and with the Windows API validate that the
password entered matches that of the password on the system.
Private Declare Function Logon User Li b " Advap i 3Z " Al i as " LogonUserA " _
(SyVal l ps zUse rna me As St r i ng . SyVa l l pszDomain As String . _
SyVal lp sz Passwo r d As Strin g. SyV al dw Logo nTy pe As Long .
Sy Val dwLogonProvider As Long . phToken As Long) As Long
Sub TestLogonUser()
Dim Successful As Long
Dim PasswordEntry As String
PasswordEntry = InputBox( " Re-Enter Password: ". "L ogon Va l idati on " )
Successful = LogonUser(CurrentUserName ...... Pa ssw o rdEntry . 2. O. 0)
662 I Chapter 32: Using the Wi ndows API I
MessageBeep
Feedback is good, right? In addition to visual feedback we can provide
audible feedback through a variety of methods. The MessageBeep
function plays the .wav file currently applied in the "Sounds and Audio
Devices" section of the Control Panel. These are the sounds we hear
when different MessageBoxes display, only we get the sound without the
MessageBox.
Sub TestMessageBeep ()
Message Beep MB_OK
Sleep 500
MessageBeep MB_ ICONSTOP
Sleep 500
MessageBeep MB_ ICONQUESTION
I Utilizing API Calls I 663
Sl eep 500
MessageBeep MB_IC ONEXC LAMA TION
Sleep 500
MessageBeep MB_ICONASTERISK
End Sub
PlaySound
Here is another API call that deals with audible feedback. PlaySound
allows us to specify which .wav file is to be played and how it is to be
played.
Public Dec l are Functio n PlaySound Lib "winmm . d l l " Alias " PlaySoundA " _
(ByVa l l pszName As String , ByVal hModule As Long, _
ByVa 1 dw Fl ags As Long ) As Lon g
Public Const SND_SY NC = &HO
Public Const SND_ASYNC = &H1
Public Const SND_LOOP = &H8
Sub TestPlaySoundA ( )
Pl aySound "C: \Windows\Media\ch i mes .wav ", 0 , SND_SYNC
PlayS ound "C:\Windows\Media\chord.wav " , 0 , SN D_SYNC
End Sub
This first example uses the "SND_SYNC" flag. This means the
chimes.wav file plays until it is finished and then the chord.wav file
plays.
Sub TestPlaySoundC ()
PlaySound "C:\Windows\Med i a\chord . wav ", 0 , _
SND_LOOP + SND ASYNC
End Sub
Shell Execute
In a previous example, we were able to discover which application was
registered to open a specific file. Shel l Exec ute actually opens the file
using the application registered to handle the file.
Sub TestShellExecuteA()
ShellExecute 0 , "OPEN", _
"Greenstone.bmp " , "C: \Windows", vbMinimizedNoFocus
End Sub
End Sub
We show two examples here. One executes the program and opens the
file minimized and the other executes the program and opens the file
maximized.
In a previous chapter we worked through an example that created
an .html file. We could use She 11 Execute to display the file immediately
after it is created. This is much better than creating the file and then
asking the user to find the file and double-click on it.
SHGetFilelnfo
SHGetFileInfo can be used for a variety of things. One thing it can do is
tell us what kind of a file we are looking at.
Sub TestGetFilelnfo()
Dim myFI As SHFILEINFO
666 I Chapter 32: Using t he Window s API I
SHGetFilelnfo " C: \ test . dgn " , SHGF I _ATTRIBUTES, myFI, Len ( myFI), _
SHGFI_DISPLAYNAME + SHGFI_ICON + SHGF I _T YPENAME
Debug.Print Replace(myFI.szDisplayName, Chr(O), '''')
Debug.Pr'nt Replace(myFI.szTypeName, Chr(O), "")
End Sub
test.dgn
Bentley ~! i croStation Design File
REVIEW
We have touched on a handful of Windows API calls here. There are
hundreds more. Some API calls deal with the display; they allow us to
draw to specific windows. Other API calls deal with reading and writing
files. Yet others deal with system memory.
Entire books and websites have been dedicated to the topic of Windows
API calls. Windows API calls are one of the reasons why we can say "Yes,
you can do that with VBA:'
33 Using Third Party
ActiveX Controls and
DLLs
In this chapter:
[B Using ActiveX controls
[B Using DLLs
667
668 I Chapter 33: Using Third Party ActiveX Controls and DLLs I
------------
: ::~N ';( ~;~: , ~
TooJboH"J~~' .. ~:~ <
When we insert a UserForm in our
Contlols I VBA project, the Toolbox dialog box
I~- A abl '@;j IiliI p- I- normally displays. Right-clicking on the
.-..J O...J ..!..i..:J "".'!J 11 Toolbox allows us to add Additional
~ Controls.
1 Delete ItJ:f
Customize Item
e,vailable Contlols:
rl8] Mi~I~-;~ft F-;ms 2.0Te.tB;;;-- · - - ;AJ,
118] Miclosoft Forms 2.0 ToggleButton .
1
'0 Miclosoft Help 2.0 Contents Control Cancel
o Miclosoft Help 2.0 Inde. Contlol
o Miclosoft Hielalchical Fle.Glid Control 6.0 (S
o Miclosoft IE Obiect 'Wlappel Sample Control
o Miclosoft ImageComboBo. Control 6.0 (SP6)
o Microsoft ImageList Control 6.0 (SP6) w:
o Miclosoft ImageList Control. velsion 5.0 (S P;
o MiClOsolt InkE dit Contlol
o Miclosoft InkPicture Contlol r Show -·,,·---- _.••• _ .. - ......,
o ~elected Items Only
Forms 2. 0 SpinButton--·· "
Location C \ 'WIN DO'WS \S ystem32\FM 20.DLL
As you scroll through the list of items, you see a great variety of
Controls. The list on each computer will be different because controls
are added when software is installed. Some of the controls shown in the
image above are installed when Visual Basic 6.0 is installed.
The fact that a control is shown in the list does not mean you can use it,
because some controls require a license. Let's look at a few controls that
are available to us.
I Using ActiveX Controls I 669
For demonstration
purposes, I will use the
I
"Calendar Control 11.0"
SUIl Mon Tu e Wed Thu Fri Sat
30 1
r 2 3 4 S control in this example.
6 7 8 9 10 11 -12 This control is installed
13 14 -15 16 17 18 19 with Microsoft Office.
20 21 22 23 24 2S 26 Select it from the list of
27 28 29 30 1 - i Available Controls and
; -' 13 ; :3 10 click the OK button.
Once it shows up in the Toolbox we can place it on our form with other
controls we want to use.
Clicking on the button displays the selected date.
i Class Member
Clas s Folderltem
Member of Shell32
Oefinrtion of interface Foldernern
Sub TestShellA( )
Dim myShell As New Shel132.Shell
Dim myFolder As Shel132.Folder3
Dim myFolderZ As Shel13Z.Folder3
Dim myItem As Shel13Z.Folderltem
Set myFol der = myShell . BrowseForFol der(O. "Br owse " . 0)
MsgBox myFolder.Self.Path
For Each myItem In myF older. Items
Debug . Print myItem . Name & vbTab & myltem.Type
Next
End Sub
672 I Chapter 33: Using Third Party ActiveX Controls and DLLs I
El fO Bentley
ID Documentation
ID Licensing
El C)!IiM-
til to
assemblies
tillD config
ID docs
til ID featuremodeling
ID icons
til mdl to
til ~i
.!~,
Sub TestShellB()
Dim myShell As New Shel132 . Shell
Dim myFolder As Shel132.Folder3
Dim myFolder2 As Shel132.Fo ld er3
Dim myItem As Shel132.FolderItem
Set myFolder = myShel l .BrowseForFolder(O, "Browse ", 0,_
"C:\Program Files\Bentley")
For Each myItem In myFolder.Items
Select Case myItem.Type
Case "F ile Folder"
Debug.Print "Folder: " & myItem.Name
End Select
Next
End Sub
I Using Exi sting DLLs I 673
Sub TestShellC ()
Dim myS he11 As New Shel132 . She 11
myShe1 1.Fi ndComputer
En d Su b
Sub TestFSOA()
Di m myFSO As New Scripting.FileSystemObject
Dim myFolder As Scripting. Folder
Dim myFile As Scripting . File
Set myFolder = myFSO . GetFolder("C:\Program Files\Bentley\MicroStation")
For Ea c h my Fi 1e I n my Fold e r . Fi 1e s
Select Case myFile.Type
Case "Bentley MicroStation Design File"
Debug.Print myFile.Name
End Select
Next
End Sub
The Immediate windovv' displays the names of the files matching the
specified criteria.
In addition to looking at files in a folder, you can get the subfolders in a
given folder and all of its subfolders as well. The next example provides a
I Using Existing DLLs I 675
Sub TestFSOB ()
Dim myFSO As New Scripting.FileSyste mObjec t
Dim myFo l der As Scripting. Folder
Dim mySubFolder As Scripting. Folder
Set myFolder = myFSO . GetFolder( "C:\Program Files\8entley " )
For Each myFolder In myFolder.SubFolders
TraverseFolders myFolder
Next
En d Sub
C:\Program Files\Bentley\Documentation
C:\Pr ogram Files\Bentley\Licensing
C:\Program Files\Bentley\HicroStation
C:\Program Files\Bentley\HicroStation\assemblies
c: \ Program Files\Bentley\HicroStation \ assemblies\ECFrame1>Jork
c: \ Program Files\Bentley\ lhcroStat ion\ assemblies\ECFrame1>Jork \ extensions
c: \ Program Files\Bentley\ lhcroStation\ assemblie3\JSpace
c: \ Program File 3\Bentley\lhcroS tation\ a33emblie3 \ JSpace \AddIn3
C:\Pr ogram Files\Bentley\HicroStation\as,emblie3\JSpace\managed
c: \ Program Files\Bentley\ lhcroS t ation\ aS3emblies\JSpace \ resource
C: \ Program Files\Bentley\HicroStation\a33emblies\JSpace\unmanaged
c: \ hogram Files\Bentley\HicroStation\ config
C:\Program File,\Bentley\HicroStation\config\appl
C:\hogram Files\Bentley\HicroStation\config\database
c: \ Program File3\Bentley\lhcroStation\ config\ system
C: \Program Files\Bentley\HicroStation\docs
Sub TestFSOC ()
Dim my FSO As New Scrip ti ng . Fi leSystemObject
Dim myDr i ve As Scripting . Drive
Dim I As Long
676 I Chapter 33: Using Third Party ActiveX Controls and DLLs I
For I = Asc("A " ) To Asc( "Z" )
If myFSO.DriveExists(Chr(I)) The n
Set myDrive = myFSO.GetDrive(Chr(I) & ":\")
If myDrive . DriveType = Remote Then
Debug.Print "Drive: " & myDrive .D riveLetter
Debug.Print "Share Name: " & myDrive.ShareName
Debug.Print "Volume: " & myDrive.Volu me Name
Debug.Print "T otal Space: " & _
FormatNumber(myDrive.TotalSize, _
0, False , False, True) & " Bytes"
Debug.Pr i nt
End If
End If
Next
End Sub
81,956,655,104 Bytes
This example gets all network drives and displays information about
each drive.
In the next example, we read an ASCII File using the File System object.
Ir.M~~x!mIl"III<ElxPlrelslsiolnlnmldlelfinledlinlclomlel~1>1I1I1I~Elm~IYIiIm~miIiMomd~u'
lro'l' ,I..
eI1~.Te!~~Fs~o~DIIIIIII~·
••
e- xSpl~(O) "#------------------------------------------------------------ SIring Module1 .T e~FSOD
e- xSpl~(1) "#" SIring Module1.TestFSOD
I- xSpl~(2) "# msconfig.cfg - Main MicroSlation Configuration F SIring Module1.TestFSOD
I- xSpl~(3) "#" SIring Module1.Te~FSOD
e- xSpl~(4) "# Currem Revision:" SIring Module1 .Te~FSOD
e- xSpl~(S) "# $RCStile: msconfig.cfg,v $" SIring Module1 .Te~FSOD
If you add a watch to the variable xSplit, you see that the file has been
successfully read and split into the variable xSplit. You can now look at
each line in the file one by one.
Now we use the File System object to write a file by creating a small
HTML file.
Sub TestFSOE()
Dim myFSO As New Scripting.FileSystemObject
Dim myFile As Scripting.File
Dim myTS As Scripting.TextStream
Set myTS = my FSO.CreateTextFile("C:\test.htm", True)
myTS.Writeline "<ht ml>"
myTS.Write l ine vbTab & "<table width=200 border=l>"
myTS .Writeline vbTab & "<tr><t d>Number</td><td>Name</td></tr> "
myTS. Wr ite l i ne vbTab & "<tr><td align=cen te r>l</td>" & _
"<td>Jerry</td></tr>"
my TS .Writeline vbTab & "<tr><td align=center>2</td>" & _
"<td>Candice</td></tr> "
myTS.Writeline vbTab & "</table> "
myTS. Wri tel i ne vbTab & "</html> "
myTS.Close
End Sub
678 I Chapter 33: Using Third Party ActiveX Controls and DLLs I
~""'~ l'f~'X,~"",,1::' ."~*<;Jf"::;J{;v1~";r~;l<',""'/*:J: t "};) ~";::'''''>:(.:w>''~....~ .... t'.}~'''Y)''''''' ...... ,- .... ,"" "'"
,~ ~;~~s~,:~~e!,,~pll!,r~J~~~~~~ ,
! File Edit View Favorites Tools Help
»
j C Back r ~ - ~ ~ ·til lf J search.... , .. .
. :............. ............... ". ... .. . . .. . . . ......., ....1.....
LAddres~ I~ C:\test.htm t'i;I. ~ .,~~ •j unks~: ,L~ ::.
2 !Candice
Nothing fancy, this is just a simple HTML file. When we wrote ASCII
text files before, we used standard VBA calls such as "Open" and "Print".
The last File System object we will look at is the Dictionary object,
which allows us to add item pairs (Key and Item) to a ready-made
collection.
Sub TestFSOF( )
Dim myFSO As New FileSyste mObject
Dim myDir As Scripting.Folder
Dim myDictionary As New Di ct ionary
Dim I As Lo ng
Set myDir = myFSO.GetFolde r ( "C:\Progra m Files \ 8entley " )
RecursiveFo l der myDir. my Dicti on ary
For I = 1 To myDict i onary.Count
Debug.Print myDictionary.Keys(I - 1) & vbTab &
my Di c t ion a r y . It ems ( I 1)
Next
End Sub
basic he l p. chIn c: \Program Files\Bentl ey\ Documentati on\ basic help. chIn \~'[
mi c r o;t ati on . chIn C: \ Pro g ram FileS\Bentl ey\ Documentati on\mic r ostati on . chIn Ii
microstationvba. chIn c: \ Program Files\Bentley\Ui c roStation\microstat ionvba. chIn r'!ri
readme_microstation. chIn c: \ Program Files\Bentley\UicroStation\ readme_microstatic , li
vba_concept. chIn c: \ Program Files \ Bentley\UicroStation\ vba_concept. chIn
Sub TestSpeechA()
Di m myVoice As New SpeechLib.SpVoice
myVoice.Speak "MicroSteyshen V. B. A. Is Great!"
End Su b
How difficult would it be to add voice/speaking capabilities to your
software without this reference? Granted, we can't always spell as we
normally do. Instead, we need to spell words phonetically (or is that
funeticly?) .
We used a Windows API call to playa .wav file. When you use the
Speech object, you can play volumes of instructions without needing to
install volumes of .wav files. You can even have your Speech object speak
dynamically, giving instructions and feedback as your application runs.
680 I Chapter 33: Using Third Party ActiveX Controls and DLLs I
VBA
For MicroStation
Here is the e-mail that is sent using CDO. And how difficult is it to add
an attachment to the e-mail?
Sub TestCDOB ()
Dim myMsg As New CDO .M essage
Dim FieldBase As String
I Using Existing DLLs I 681
From : myaddress@myserver,com
To: youraddress@yourserver.com
Cc:
Subject: Testing COO Email
VBA
II For MicroStation
http://support,microsoft.com/kb/22435 7I
to another link, "Download the DsoFileSetup:' This is what we want
because MicroStation design files are OLE documents. Another term
used to describe this type of file is "Structured Storage" documents.
What does this mean?
682 I Chapter 33: Using Third Party ActiveX Controls and DLLs I
In MicroStation, go to the File> Properties menu item. When the File
Properties dialog box opens, click on the Summary tab.
Keywords: ~[=========:;
Comments: ~. _ __ _ _ _----.-J
Milestones:
: Manager:
Cancel
These properties may look familiar as they are in Microsoft Word and
Excel files, among others. We can read and write these properties in .dgn
files using VBA when a design file is open. The DSOFile reference
allows us to open any structured storage file to read file properties or
write/ create them, even if the application that created the file is not
installed. Let's take a look.
Sub TestDSOA ()
Dim myDSO As New DSOFile . OleDocumentProperties
Bentley'Systems, Inc.
myDSO .Op en "C:\ test . dgn " , True
MsgBox myDSO . SummaryP rope rties.Author
myDSO . Close
End Sub
The author of the file C \test.dgn is "Bentley Systems, Inc:' If we attempt
to read or write properties of a file that is open in an application, we may
be prohibited from doing so.
Our next example writes properties to the test.dgn file.
Sub TestDSOB ()
Di m my DSO As New DSOFile . Ol eDoc umen t Propert i es
myDSO . Open "C: \ t est .d gn ", Fa l se
my DSO . Su mm aryProperties . Author = "Jerry Wi nters "
my DSO . SummaryP r operties.Category "MicroStat i on VBA "
myDSO . SummaryPropert i es . Key words = "VBA "
myDSO . Save
myDSO . Close
I Using Existing DLLs I 683
End Sub
If we write properties to a file, we must save it before we close it.
I::~:, ~~~~;~
Here are the results
in Window s'
Explore r Properties
dialog box: Author:
\. . . . . . . . . . . . .-.. . . ... . . . . .... . . . . . . . ...... . . . -.. . ....... . . . ..... . . . . . ....... . . . . . . . . .., I
Category: I~'licro5tation liSA I
Keywords: I'-
VSA
__ _ --~~_-
_ __ _ _ _-_ . _-_---ll
Comments :
Advanced »
Sub TestDSOC ()
Dim myDSO As Ne w DSOF i le . Ol eDocumentPropert i es
myDSO .O pen "C: \t est . dgn " , True
Deb ug . Pr i nt myDSO . SummaryProperties . Appl i cationName
Debug . Print myDSO . SummaryProperties . Author
De bug . Prin t myD SO. SummaryPropert i es .B yte Count
Debug . Print myDSO . SummaryProperties . Category
Debug . Print myDSO . SummaryPropert i es . CharacterCount
Debug .P rint myDSO . SummaryProperties . CharacterCountWithSpaces
Debug . Print myDSO . Summa ryP roperties . Comments
Debug . Print myDSO . SummaryProperties . Company
Debug . Pri nt myDSO . SummaryProperties.DateCreated
Debug . Print myDSO . SummaryProperties.DateLastPrinted
Debug . Pr int myDSO . SummaryProperties . DateLastSaved
684 I Chapter 33: Using Third Party ActiveX Controls and DLLs I
Debug . Print myDSO .S ummaryProperties . Hidde nSlideCount
Debug.Pr i nt myDSO.SummaryProperties.Keywords
Debug.Print myDSO.SummaryProperties.LastSavedBy
Debug.Print myDSO.SummaryProperties.LineCount
Debug.Print myDSO.SummaryProperties.Manager
Debug.Print myDSO .S ummaryProperties.MultimediaClipCount
Debug.Print myDSO . SummaryProperties.NoteCount
Debug .Pri nt myD SO.Su mmaryProperties.PageCount
Debug.Print myDSO .Su mmaryProperties .Parag raphCount
Debug . Print myDSO.SummaryProperties.PresentationFormat
Debug.Print myDSO.Su mmaryProperties.Rev isio nNu mber
Debug.Print myDSO.SummaryProperties.SharedDocument
Debug . Print myDSO.SummaryProperties.SlideCount
Debug.Print myDSO . SummaryProperties.Subject
Debug.Print myDSO . SummaryProperties . Template
Debug. Pr i nt myDS O. Summa ryProperties.Thu mbn ail
Debug . Pr i nt myDSO.SummaryPropert i es.Tit l e
Debug . Pr int myDSO . SummaryPropert i es . TotalEd i tT i me
Debug . Pr int myDSO . SummaryPropert i es . Version
Debug . Print myDSO.SummaryProperties.WordCount
En d Sub
Some of the Summary Properties shown here are read-only. For
example, we cannot modify the 'DateCreated' property.
Not all files are 'Structured Storage' files. One example is a .txt file
created in Notepad. Even though it is not a structured storage file, when
it resides on an NTFS hard drive, some summary properties are
available. Be careful with non-structured storage files. It may look as
though you are entering file properties, but if you e-mail the file or place
it on a non-NTFS drive, the file properties do not follow the file because
the properties are not stored in the file. Instead, they are stored with
(actually alongside) the file.
Sub TestDSOO()
Dim myDSO As New DSOFile .OleDocu mentProperties
my DSO . 0 pen "C: \ t est. txt " . True
MsgBox myDSO . SummaryProperties . Author
myDSO . Close
End Sub
I Using Existing DLLs I 685
TestDSOD looks very much like TestDS OA, only we are opening a differe nt
file. TesUxt is a standard ASCII file. In Windows Explorer, right-click on
the file and select Properties to display a few tabs.
II General l~mmar~L__________________- ,
I Title: ~'--s-am-pl-e,-tx-t f-ile- - - - - - - - - - - - - - - - - , i I
I
Subject:
~------~
~ation VBA I
Author: r J~;~yWi~t~~~ -_---m· -----------·-----'----·-----··1
Category: [ dsofile
~._.~ •• ~ •• _ . _ •• _M .... _ .. __ ••• __ ._._._ .... _ ... _. _ _ •• _ ••••• __ _ _ .. _ •••• _ _ _ •• M •••••••••••• _ _ .... _.H •••••• H ..... H ••••
I'
~' I i I
- - - - - - - - - - - - -_ _ _ ~-_I
" I
Advanced> > I
Low [ Cancel
- - ---
If you compare this dialog box with the one a couple of pages ago, you
discover that this dialog does not have a Custom tab. This indicates that
the file is not a structured storage file and that the properties shown are
due to NTFS functionality. So, you can visually discern the difference
between NTFS properties and structured storage properties. And the
macro TestDSOD runs even though the file is not "Structured Storage:'
But how do you know whether a file is OLE (Structured Storage) or not?
Sub TestDSOE ()
Dim myDSO As New DSOFi le .O l eDocumentProperties
'F irst we try a txt file
myDSO.Open "C: \test . txt ", True
If myDSO.IsOleFile = False Then
MsgBox "The file is not Structured Storage ."
Else
MsgBox "Structured Storage File Found. "
End If
myDSO.Close
686 I Chapter 33: Using Third Party ActiveX Controls and DLLs I
' Now f or th e DGN File
my DSO. 0 pen "C: \ t est . d gn " , Tr ue
If myDSO.IsOleFile = False Then
MsgBox "The file is not StrJctured Storage."
Else
MsgBox "Structured Storage File Found."
End If
myDSO.Close
End Sub
The "IsOleFile" property says whether the file is an OLE Document
(Structured Storage) or a non -OLE Document. This is important to
know because non-OLE documents are limited in their use of
properties.
In addition to SummaryProperties (standard properties), you can create,
read, and write custom properties.
Sub Te stDSOF ()
Di m myDSO As New DSOFil e .O l eDocum entPr ope rtie s
myDSO . Open "C:\test.dg n" , Fals e
If my DSO . IsO 1e Fi 1e = True The n
myDSO.C ust omProper t i es.Add "For Book ", _
"Lea rni ng Mi c roSt at i on VB A"
myDSO . Save
End I f
myDSO .Cl ose
End Sub
In this example, we add a custom property to the specified file IF the file
is an OLE File (Structured Storage). After adding the custom property, it
I Using Existing DLLs I 687
Name: v ,i
Type: !Text vi
!. ......- .. ~- ..----.-----.---..---.---.-------j
Value: r----------------------------J
Properties: Name Value Type
[F.:~-;·B~~k--: Learning ~licro5tation VBA Text
),-,
1_ _ -
OK ,II Cancel I
The ability to add Custom File properties is powerful. You may want to
store information regarding the number of cells in a design file in a
custom property. If you do, VBA programming (from within
MicroStation or any other VBA environment) can read and write the
property, even if MicroStation is not installed.
A link was provided to the DSOFile.exe download page earlier. The file is
also located on the CD that accompanies this book.
For additional information regarding reading and writing file
properties, Microsoft's website has documentation and code examples
on it. Searching for "Dsofile" on the Internet gets a large number of
results as well.
688 I Chapter 33: Using Third Party ActiveX Controls and DLLs I
REVIEW
One of the powers of VBA is that you are not limited to the calls directly
exposed by VBA. You can use programming components developed by
others to speed development and augment functionality. We discussed a
few references that, when added, can add significant power to the
software you develop.
Opening the References dialog box in VBA, adding a reference, and
opening the Object Browser are great ways to familiarize yourself with
the functionality exposed by any references on your computer.
34 Working With Excel
In this chapter
[8 Connecting to Excel
CONNECTING TO EXCEL
There are three ways to 'connect' to Excel. We will begin by using
"GetO bj ect".
GetObject
689
690 I Chapter 34: Working With Excel I
Dim myExcel As Object
Set myExcel = GetOb j ect ( , " Excel.Application")
End Sub
If Excel is not ~~~!c,!5.!'!t, !1s.~~l ~as_if ,,, ;: . ',.. ~.. .1 :,.', ' " .. ",' K~ ,,~
we attempt to
'get' Exce l.
5,:.ontin',e
When we see this error, we know we just attempted to "Get" Excel and
Excel was not running. If Excel is running, the macro Test Ex eel Aruns
without any problems. But what does TestExcel Ado?
We declare a variable, myExcel as an Object. Then we Set the variable to
the return value of GetObj eet. After the variable myExcel is set, it is the
Microsoft Excel Application. Everything we do to the variable myExcel
impacts Excel.
When we declare a variable as an 'Object', we are performing "Late
Binding". This means that before the Object is Set, the Object doesn't
know who or what it is. When we declare a variable as a specific type of
object, we are performing "Early Binding".
Adding a Reference to the Microsoft Excel Object Library does wonders
for our programming efforts.
~
Available References:
~
'-. ".'
.. --........... ---.-.. -..- ...-----.. -..-..- ....-..-- ............ -...---....- .........-..- ....'.c.",
:....1Visual Basic For Applications •__:'
:;;: Bentley ~licroStation DGN 8.9 Object Library :;g,
e.;;: OLE Automation
;~L.. _.. , Browse". I
Once a Reference is made, we can declare variables as specific types of
Objects.
Sub TestExcelB ()
Dim my Ex c e 1 As Ex c e 1 . APP1 i cat ion
Set my Ex eel = Get 0 b j e c t ( , " Ex c e 1 . APP1 i cat i on " )
End Sub
I Connecting to Excel I 691
Sub TestExcelC ()
Dim myExcel As Excel.Application
Set myExcel = GetObject(, "Excel. Application" )
msgbox myexcel.
End Sub " ~i~~tii.~i~Mi~i~~9~r~ ....... . .... .. . . .... . .. . ............................ !~
CreateObject
If Microsoft Excel is not running or if we want to create a new instance
of the Excel.Application, we can use Crea teObj eet.
New
When a Reference to the "Excel Library" has been added to our YBA
project, YBA understands what an Excel.Application Object is. If a
Reference has been added, we can use the New keyword to 'create' an
Object.
Sub TestExcelD2 ()
Dim myExcel As New Excel.Application
my Ex c e 1 . Vis i b 1 e = True
my Exce l . Wor kbook s. Add
End Sub
Using New instead of CreateO bj eet can be useful because we do not need
to supply the Class "Excel. Application" as we do with Cr ea t eOb j eet. And
why is this useful? Because it is possible to have multiple versions of an
application that has been exposed to YBA and using the New keyword
will 'create' the version that is referenced.
GetObjee t, Cr eateObjee t, and New are the methods we use to 'connect' to
Microsoft Excel. When we add a Reference to the Microsoft Excel
Object Library, we can declare variables as specific types of objects
(Early Binding). YBA helps us as we work with these variables by
performing syntax checking and also helps us know what properties,
methods, and events we can utilize.
50 60
500 600
1000 1200
1500 1800
2000 2400
2500 3000
3000 3600
v,
>U
Sub TestExce l E( )
Dim myExcel As Excel.Ap plicatio n
Dim mySheet A As Work s heet
Di m myS heetB As Worksheet
Dim mySheetC As Worksheet
Dim mySheetD As Worksheet
Set my Excel = GetObject(. "Excel.Applicat i on " )
Se t mySheetA = myExce 1 . Act i veSheet
Set mySheetB = myExcel . ActiveWorkbook.Worksheets( "SimpleGrid " )
Set mySheetC = myExcel.ActiveWorkbook .Worksheets( "ComplexGrid " )
Set mySheetD = myExce l .Ac t ive Workbook. Worksheets( "Sheet3 " )
Debug . Print mySheetA.Name
Debug . Print mySheetB.Name
Debug.Pr i nt mySheetC . Name
Debug.Print mySheetD.Name
Set mySheetB myExcel . ActiveWorkbook.Worksheets(l)
Set mySheetC myExcel . ActiveWorkbook . Worksheets(2)
Set mySheetD myExcel.ActiveWorkbook.Worksheets(3)
694 I Chapter 34: Working With Excel I
Debug.Print mySheet B.Name
Debu g . Print my SheetC .N ame
Debug.Print mySheetD.Name
End Sub
We can address Worksheets by getting the ActiveSheet or through the
Worksheets Collection by Name or by Index.
Now that we can get the Worksheets, let's see what we can do about
getting individual Cells.
Sub TestExcelF ()
Di m my Exc e 1 As Ex c e 1 . APP1 i ca t i on
Dim myS he et A As Wor kshee t
Set myExc el = Get Ob j ect( . "E xce l .A ppli cat i on " )
20
Set mySheetA = myExcel .Acti ve Workbook .W orks he ets( "Si mpl eGr id" )
MsgBo x myShee tA . Range (" B1") . Text
End Sub
One of the ways we can address individual Cells is by getting to them
through the Range Object. When we use the Range object, we get the
cell by its address. ''AI'', "C6': "F9", etc. Using an Address such as ''A4'' is
helpful because we can directly relate that to what we see in Excel.
The other way we work with Cells in Excel is through the use of the
Cells Collection.
When we work with the Cells Collection we specify the RowIndex and
then the ColumnIndex. Row 1 in Excel has a RowIndex of 1 and
Column "J\, in Excel has a ColumnIndex of 1. We need to make sure we
specify the Row before the Column when working with the Cells
collection.
Sub TestExcelG ( )
Dim my Ex c e 1 As Ex eel . APP1 i cat ion
I Workbooks, Worksheets, Ranges, and Cells I 695
End Sub
A MessageBox displays the text found in the cell on the 4th row and 6th
column.
Getting a Cell based on its Rowand Column does not seem as easy as
getting it based on its Address. So, why would we go through the trouble
of Rows and Columns?
Sub TestExcelH()
Di m myExcel As Excel. Appl i cat ion
Dim mySheetA As Worksheet
Dim CurRow As Long
Dim CurCol As Long
Set myExcel = GetObject(. "E xcel.Appl ication " )
Set mySheetA = myExcel .A ctiveWorkbook .Worksheets ( "SimpleGr i d" )
For CurRow = 1 To 7
For CurCol = Asc( "A" ) To Asc("F")
Debug . Pr i nt mySheetA.Range(Chr(CurCol) & CurRow)
Next CurCol
Next CurRow
End Sub
Sub TestExcelJ ()
Dim my Exc e 1 As Ex c e 1 . APP1i cat io n
Dim mySheetA As Worksheet
Dim CurRow As Long
Dim CurCol As Long
Set myExcel = GetObject(. "E xcel.Application " )
Set mySheetA = myExcel .ActiveWorkbook.Worksheets("SimpleGrid")
For CurRow = 1 To 7
For CurCol = 1 To 6
Debug.Print mySheetA.Ce lls(Cur Row. CurCol)
Next CurCol
Next CurRow
End Sub
Both TestExcel Hand TestExcel J print the values of a grid of cells to the
Immediate Window. TestExcel H can do this easily because we are
696 \ Chapter 34: Working With Excel \
dealing with columns A to F. The same code would work with columns
A to Z. But what happens when we get to column ''AX'? When we work
with Range objects, we specify the column with its letter designation of
anything from ''1\' to "IV". Writing code that flows from "z" to "AX' is
not difficult but cumbersome. When we use the Cells collection, we
simply specify column 27 after we finish with column 26 without
worrying about whether we are going from Column Z to AA, AB, and so
forth.
So, which is best? The Cells Collection or the Range Collection?
As we have discussed, each has its strengths and weaknesses. Providing a
Rowand Column numerically is easy to do but difficult to 'translate' the
Cell Column to a lettered Column in Excel. What is the lettered Column
Name associated with column 2ll?
Ranges are great especially when dealing with a relatively small set of
data (Columns A through Z particularly) but become more difficult to
work with when we get to Columns AA through IV. Ranges, however,
can also consist of multiple cells (from Al through D4 for example). So,
that is a definite strength.
If we work with Cells (providing numbers for the columns as well as the
rows), we can help ourselves a little by changing a setting in Microsoft
Excel.
Tools > Options in Excel displays the Options dialog box. Clicking on
the General tab allows us to turn on "Rl Cl reference style". When
"RlCl reference style" is turned on, Columns in Excel appear as
Numbers instead of letters. The formulas in Cells are modified to use
the RlCl style so they will look odd but as far as programming for
Microsoft Excel, seeing the Column Number is a lot easier than
I Workbooks, Worksheets, Ranges, and Ce ll s I 697
counting out 'AP.:.', 'A B", 'AC" to fi nd out what the Colum n Index is of
Column "DC".
Settings
o !?rompt for workbook properties
~~i~:~~:tt:;n:::IE!t!on$ o Provide [eedback with sound
~ Function tooltips 0 £00'" on roll with IntelliMouse
~ flecently used file list: 14. -..-····-· ~-1 entries
I't£eb Options... I [ser~ice Options... I
OK I[ Cancel
Sub TestExcelU )
Dim myExcel As Excel . Application
Dim mySheetA As Worksheet
Dim CurRow As Long
Dim CurCol As Long
Dim myCe 11 As Excel. Range
Set myExcel = GetObj ect ( . "Excel . Application")
Set mySheetA = myExcel . ActiveWorkbook.Worksheets("SimpleGrid " )
698 I Chapter 34: Workin g With Exce l I
Fo r CurRow = 1 To 7
For CurCo l = 1 To 6
Set myCell = mySheetA . Cells(CurRovl, CurCo')
Debug.Print myCell . AddressCTrue, True, xlAl) & vbTab &
myCell . Addr ess(True , True , xlR1Cl)
Ne xt CurCo l
Next CurRow
End Sub
In this example, the selection was "B2" through "B7" (2,2 to 7,2).
I Workbooks, Worksheets, Ranges, and Cel ls I 699
The colon (:) tells us "B2" through "B7" have been selected. There are
other ways to select cells in Excel.
>
Here we see what we get when the range of "B2" through "BS" are
selected AND "D2" AND "DS".
In the previous examples, we knew exactly from which cells we wanted
to get values. Our next example is going to display the values of the
selected cells. We will begin by assuming that a range of cells is selected
instead of individual cells.
Te stE xc el Nand TestExcel P are very much alike. They accomplish the
same thing. In Tes tE xeel P, we are 'extracting' the address as well. So, if
each of these is doing the same thing, which one is the best one? Fewer
lines of code is good. Knowing how to break out the Address is good
too. Each has its benefits. One is not necessarily better than the other,
they are just different.
Here is another macro to consider. Instead of extracting the Address as
''A 1" style, we will extract it in (Row, Col) style.
Sub TestExcelR ()
Dim myExce l As Excel . App l ic at ion
Di m myShe et As Worksheet
Se t my Exce 1 = GetO bj ect ( , "Ex ce l. Application " )
Set myS heet = my Exce 1 . Act i veSheet
'Give B1 a new Value
mySheet . Range( "B1" ).Value = 70
' Give B2 a new Formula
mySheet . Range( "B 2" ) .F ormula = "=B$1*$A2*52 "
' Copy B2 to the Windows Clipboard
mySheet.Range( "B2 " ) . Copy
' Select B2 through F7
mySheet . Range( "B2 ", "F7 " ) .Select
' Paste copied formula to selected cells
mySheet.Paste
' Select B2
mySheet.Range( "B2 " ).Select
' Reset Cut/Copy Mode
myExce l .CutCopyMode = Fal se
End Sub
702 \ Chapter 34: Working With Excel \
Sub TestExcel S ()
Dim myExcel As Exce l .Appl ication
Dim myWB As Excel . Workbook
Dim myWSA As Excel. Worksheet
Dim myWSB As Exce l . Wor ks heet
Dim myWSC As Excel. Worksheet
Dim RadValue As Double
Di m InchValue As Double
Dim Fe etValue As Double
Dim CurRow As Long
Set my Ex c e 1 = Get 0 bj e c t (, "E xc e 1 . APP1 i cat ion" )
Set myWB = myExcel.ActiveWorkbook
Set myWSA myWB . Worksheets( "Sheetl " )
Set myWSB = myWB.WorksheetsC"Sheet2 " )
Set myWSC = myWB.Worksheets( "Sheet3 " )
' Merge Header Rows
myWSA. Range( "Al " , "Dl " ). Merg e Tr ue
myWS B. Range( "Al", "Dl"). Merge Tr ue
myWSC.Ra ngeC "Al " , "Dl " ).Merge True
CurRow = 3
For RadValue = 0 To 36 0 Step 5
myWSA.Range ( "A" & CurRow) = RadVal ue
myWSA . Range( "B" & CurRow).Value - RadValue * Atn(l) * 4 / 180
CurRow = CurRow + 1
Next RadValue
CurRow = 3
myWSB . Range( "A2 " ) = "Inch "
myWSB . Range( "B2 " ) = "Cent i meter "
For In chVal ue = 1 To 36
myWS B.Rang e( "A" & Cur Row) = Inch Val ue
myW SB . Ra nge("B" & CurR owl .Formul a - "-A" & CurRow & " * 2 . 54 "
Cur Row = CurRow + 1
Nex t I nchValue
CurRow = 3
myWSC . Range( "A2 " ) = "F eet "
myWSC .R ange( "B2") = "M iles "
For Fee tValue = 0 To 20000 Step 1000
myWSC.Range("A" & CurRow) = FeetValue
myWSC.Range( "B" & CurRowl.Formu l a - "-A " & CurRow & " / 5280 "
CurRow = CurRow + 1
Next FeetValue
End Sub
Tes tExce 1S is using three different Worksheets in the same Workbook.
We do not need to switch to the actual Worksheet before we can use it,
we simply address it by its name (Sheetl, Sheet2, Sheet3).
Excel is used to house a great deal of information. One thing it can be
used for is holding X, Y, and Z coordinates for points. Let's take a look at
our first example.
704 I Chapter 34: Working With Excel I
We use the Excel Function RAN 0 to help us generate a random number.
This helps us generate points that fall within a specific area.
A BC
The X and Y values are set to be randomly generated between -50 and 50
whereas the Z value will be calculated to be between -25 and 25.
The RA N0 function re-calculates the values whenever the Worksheet is
recalculated. The values don't 'stick', so one person's values will differ
from another person's values.
I Workbooks, Worksheets, Ranges, and Ce lls I 705
Now that we have seen the formulas, let's take a look at the values
generated.
A BC E
1 X Y Z
2 -2208716598" 33.06775051 10.80048308 1
3 -6.328729698 -33.55681358 -15.12641372 2
4 34.56159917 -10.503424 6.740530447 3
5 -4 .622206053 2807424377 11.58952008 2
6 -29.87002472 -42.94468857 -1803490077 1
7 41.69913054 -25.40802339 17.79778593 2
8 18.51114764 0.302771807 -12.71775582 3
9 -43.30360124 -4.219122549 17.52240842 2
10 27.57192593 36.50908479 -5.833780353 1
11 27.82085713 -1.916510652
... . ................•.
16.59443405 2
12 47.68307758 22. 11381557 -8.423401139 3
13 -49.79771456' ;)O-.S208630g:fo97469319
. -- ._._. __.__._._.'" -_._-----_.._-_.--_. ' 2
14 -28.44507751 11 .91563398 23.67553777 1
15 15.35135842'- -'-7~715i8G75 ---2246271813 2
16 1621397367 f4071189ii ':5470716498' 3
17 .... ~94??~3~_~~. 4561203874 ' 16S.74~§187 ; 2
18 -36.0 12428862427163771 ' -5.996325708 l'
19 3443S15521: ' 14 51513287; :12j1695913' . . 2 '"
20 . . ... ':25.498429 i 9' . ..... 1:2 18440165 ' . ........ ... :46610566 ; ' 3'
21:1.344~9S2 l -3963885911' -1434005614 " 2
22 -4035505243': 15:5432170i -7.858884602' 1
23 -1846141973 , .3S73125351 1 " :19.68034631 ' 2
24 .. . 37294 10466' :33s'47663-75 -1124281S18 ' 3
25 -6.704128391"····- :1S.2653331' ··· :2967s7557,· 2
. . - 1'
26 -.-----.--
.. "1
1.553724653'-- 2912092628 4542'2'73424 '
..- ...----.. - ..•- .., . _._-_ .•. _-- •.- -•....-. -t----·---···--·-·----····-- --';'
For this example, the number of rows is not fixed. We can have
anywhere from 1 data row to 65,536 rows. The code we will work with
begins by looking on Row 2 and continues executing until it finds a row
where Column A is empty.
Sub TestExcelT ( )
Dim myExcel As Excel.Applicat i on
Dim myWSA As Exce l .W or ksheet
Dim CurRow As Long
CurRow = 2
Set my Ex c e 1 = Get 0 b j e c t ( , " Ex c e 1 . APP1 i cat ion" )
Set myWSA = myExce l .ActiveWor kboo k .Worksheets("Sheetl")
While myWSA.Cells(CurRow, 1) <> ""
Debug . Print myWSA .Ce lls(CurRow, 1) & " " &
myWSA.Cells(CurRow, 2) & " " &
myWSA.Cells(CurRow, 3 )
CurRow CurRow + 1
Wend
myWSA . Calculate
End Sub
706 I Chapter 34: Workin g Wi th Excel I
TAG EXTRACTION
When we discussed Tags in a previous chapter we stated that we would
see an example of extracting Tag information into Microsoft Excel. We
will begin by modifying the macro ExportFo l derTagsToHH1L. In this
708 I Chapter 34: Working With Excel I
m acro, we had created an HTML document that displays the Tag
information of files in a specific folder.
'New Declarations
Dim myExcel As Excel.App l ication
Dim myWS As Excel.Worksheet
Dim CurRow As Long
'New Code
Set myExcel = New Excel.Appl ication
my Ex c e 1 . Vis i b1e = True
myExcel . Workbooks. Add
Set myWS myExcel . ActiveSheet
CurRow = 2
'Header
CurR ow = Cu rR ow + 1
ITag Extraction I 709
'Write to Excel
myWS . Ce l ls(CurRow, 2) = TargetTagset
myW S. Cel ls (C ur Row , 3 ) = _
myTag.TagOefinitio nName
myW S. Cel ls (CurRow . 4) = myTag . Value
myWS.Ce l l s ( CurR ow , 5) = myTag . I D. Hi gh
my WS. Ce ll s(C ur Row, 6) = myTag. I O.L ow
CurRow = CurRow + 1
Wend
End Select
Next
myOGN.C l ose
End Se l ect
Next
End Sub
710 \ Chapter 34: Working With Excel \
The code here is very similar to that in Chapter 28. We open each file
"PorProgram", and extract Title Block Information from the Tags in the
files. We are doing a little bit of formatting as well. We merge a few cells
where the file name is, and draw a border around it. We also change the
font.Bold property of the 'headers' to True.
Getting the Tag Name and Value are helpful in a variety of areas. But
getting the ID values (both High and Low) are helpful as well. Now that
. the Tag information is inside Excel, we can make changes to the Tags in
Excel and then run a Macro to update the .dgn files .
If, for example, the Job Number is changed from "BSBOO" to "BSBOOA':
we could make the change in Excel and run the macro TestExcel X to
update the BSBOOAE30 1-Elevations.dgn file.
1: 100
REVI EW
Any area we have already discussed relating to Element Creation, Data
Extraction, etc., can be used in conjunction with Microsoft Excel. We
have used Excel to extract data from MicroStation, to create data inside
MicroStation, and to modify data inside MicroStation. Those who use
Microsoft Excel in conjunction with MicroStation will find that many
manual, time-consuming, tedious, error-prone tasks can be
accomplished with the marriage of these two great technologies.
35 Working With Databases
(ActiveX Data Objects)
Access, Oracle, DB2, SQL Server. When there's data to be stored, there is
no shortage of Database platforms to store it. Rather than spending time
on each Database, we will devote our time to learning about ActiveX
Data Objects because with ActiveX Data Objects, we can 'talk' to each of
these database products.
In this chapter:
[B Primer on ActiveX Data Objects
[B UDL File Basics
[B Connections and Recordsets
[B Structured Query Language Essentials
[B Extending ActiveX Data Objects
[B Examining Database Schema
[B Excel Files as Databases
713
714 I Chapter 35: Working With Databases (ActiveX Data Objects) I
IAOOOB v I ~ • ~ }a 'W
:======~
L - I_ _ _ _ ---------"vi '" ~___.___________.
Classes Me mbers of 'Connection'
rffJ ADCPROP _ASYNC1 ~! ,.,~ Exec ute
rffJ ADC PROP _AUTOR E ;:! fJ ExecuteC omplete
rffJ ADCPROP _UPDATE ~' fJ InfoMessage
,tfJ ADCPROP _UPDATE ~ Iso lation Leve l
rffJ AffectEnum ~ Mode
,tfJ BookmarkEnum .,,~ Open " , " ,
~ Comm a nd .,~ Ope nSchema
rffJ CommandTypeEnur ~ Properties
rffJ CompareEnum ~ Provider
~[¢.§~~~§ii9.~ ... . . ! ~i .,~~ Ro li ba ckTran s
Sub Ollen([ConnectionSlring As Siringj, [UserlD As Siring], [Password As Siring j. [Options As Long = -1J)
Member of ADODB .C()l1neetion
When we select the "Open" method, we can see the Open declaration.
A few Objects worth examining for a moment are "Connection",
"Recordset", and "Field". We will be working with these Objects and
their Methods and Properties. Look for Methods such as Open, Update,
Execute, and AddNew.
In a nutshell, ActiveX Data Objects allow us to open a Database, query
its records, modify its records, add new records, etc. Before doing much
with ActiveX Data Objects, however, we need to have a database to work
with.
The USGS (United States Geographic Survey) maintains a system
named the "Geographic Names Information System" (GNIS) . The
Geographic Names from several states have been imported into a
Microsoft Access Database named PlacePoin ts.mdb. This file is located
on the CD accompanying this book. This will be the first database we
work with in this chapter.
716 I Chapter 35: Working With Databases (ActiveX Data Objects) I
Here is a screen capture of some of the data in this database. Notice the
Fields (Columns) and each Record (Rows) .
49045
14022 Tooele ·.i(04S ' 4068083 ·112.26222
14023' L~~e. PoinICemelery . cemelery ;Tooele 49; Q~!i.
,4Q4017N , 1121545.W , 40671}9. ·11~26?5..
14024 1454454 UT ... Lak. e P.9inllnler"hange ,cr9ss.ing [Tooele 49. 045 ' 404136N 1121547W 406~.~~3 ·112.26306
14025 ... !43!6.1 1,.UT . !,ake ~oi.~\.~u. ~ .~lion ... ;ppl...... iTooel.e 49.045 T404323N . 1 1·21 :i~iw 40.72306 .1122.2.5.28
14026 ' 1~35839UT Lake Powell Overlook . Iocale ;Garfield
" 4iioil ' : 375302Nll02508W 3788389 ·110.418B9
14028' 1429440UT ;La~e. Ridg;; ·"··~f r~dge · ! Ri~h ·~·: ~$l@.:.l~"57bji-J ill1 0?2i'l\iji .95()83 ·1 i 109083
l!q~l _1!5.1.§Q! .t,!T • L~~id~_._ ..... ~ el'L . __ .:.~alL~~'!.... _._~Q~.~ .. _._l..4.Q.41.5EN ~'!'!.?[J~8W ~Q §9~1!!.-1110716!
1~9}.!. __14.!2420 !!I. ~,,-k!.~g~ . __ .. _ ji.!!g~... 'I\I~e!: __ . ~Q5.2 ...J1171 ~N _! 1!29~'I\I. 4 128~33 ·1 114~67
. ':Ji~~~L:j~~-1~~~L~ It!~:~:~~;· . t::~~:· ..f~~chhe .. ~~;~; -T1·m~;~ ~11~m~~ 1 :1~~~~ :11 ;~~~~
Advanced sellings:
~------~-----------------------------.
!0 Files and Folders A .. '
. 0 Automatically search for network folders and printers
o Display file size information in folder tips
o Display simple folder view in Explorer's Folders list
o Display the contents of system folders
o Display the full path in the address bar
o 0 isplay the full path in the title bar
o Do not cache thumbnails
o Hidden files and folders
o Do not show hidden files and folders
o Show hidden files and folders
Hide extensions for known file types
Restore Defaults I
3 In the View tab, uncheck the "Hide extensions for known file types".
4 Right-click in the folder where the UDL file is to be created and
select New> Text Document.
,i. ;;;;------------;:
I. ij ~;~~~~~~; ~~;i;e· ~~~ess Application
Arrange Icons By .' ~ I~icrosoft PowerPoint Presentation
i.__~=f!=:_~._... _ ___ ....... j (!'] Paint Shop Pro 9 Image
! Customize This Folder, .. ........··......·....·....1 ~ ~ticrosoft Office Publisher Document
~ Play List Document
,.__p_ro_p_e_
rt_
ie_
s ______________ ~:Ir-~------------------------
If you change a file name extension, the file may become unusable .
7 When asked if you are sure the file extension should be changed,
click the Yes button.
The new UDL file is created. Now we need to open the UDL file and
tell it which driver we want to use (based on the database we are
connecting to) and where the database is located.
8 Open the UDL file by double-clicking it in Windows Explorer.
I
Provider ! Connection Advanced ,Ail I ,Provider I
Connection Advanced All I
Select the data you want to connect to: Specify the following to connect to Access data:
OLE DB Provider s
1. Select or enter a .database name:
Connectivity Service Provider IC: \M icrostation VBA \ PlacePoints, mdb
MediaCatalogDB OLE DB Provider
MediaCatalogMergedDB OLE DB Provider 2, Enter i~formation to log on to the database:
MediaCatalogWebDB OLE DB Provider
User name: IAdmin
Microsoft ISAM 1,1 OLE DB Provider
Microsoft Jet 3,51 OLE DB Provider .e~ssword : 1'"1- --------- --
Microsoft OLE DB Provider For Data Mining Services r;; Jl.lank password r Allow l aving password
Microsoft OLE DB Provider for Inde.ing Service
Microsoft OLE DB Provider for Internet Publishing
Microsoft OLE DB Provider for ODBC Drivers
Microsoft OLE DB Provider for OLAP Services
Microsoft OLE DB Provider for OLAP Services 8. 0
Microsoft OLE DB Provider for Oracle
Microsoft OLE DB Provider for Outlook Search
Microsoft OLE DB Provider for SQL Server
Microsoft OLE DB Provider for Visual FoxPro ~I
lest Connection I
Sub TestConnectionA ()
Dim myDB As New ADODB.Connection
myDB .Ope n "f il e name=C:\MicroStation VBA\PlacePoints.udl"
myDB.Close
End Sub
In our first example, we open a Connection by using the UDL file we
just created and then we immediately close the database connection.
Notice how the variable myDB is declared. It is declared as a "New
ADODB.Connection" .
In addition to declaring a Connection as a "New ADODB.Connection",
we can declare it as an ''ADODB.Connection'' and then set the variable
to a "New ADODB.Connection" as we see in TestCo nne ct i onB.
Sub TestConnectionB ()
Di m myDB As ADODB . Co nnect i on
Set myDB = New ADODB . Connect i on
my DB.O pen "f i l e name=C : \ Mi cr oSt ation VBA\ Place Poin t s .u dl "
myDB . Cl ose
End Sub
Instead of Declaring the Connection as New, we set it to a New
ADODB.Connection on the following line. Aside from the fact that the
720 I Chapter 35: Working With Databases (Active X Data Objects) I
second example uses an additional line of code, the difference between
the two methods is negligible.
Opening and immediately Closing a Connection does not help us at all.
Let's do something with the Connection before we close it now.
Sub TestConnectionC()
Dim myDB As ADODB.Connection
Set myDB = New ADODB.Connection
myDB.Open "file name=C:\MicroStation VBA\PlacePoints.udl"
myDB . Execute "Create Table PlaceNotes " & _
" (Unique I D Counter, PlaceID Long) "
myDB.C l ose
End Sub
The Execute Method allows us to execute SQL statements on the
Connection Object. In the above example, we create a new Table named
"PlaceNotes" with two fields. Here are a few additional examples of
using the Execute Method.
TestConnecti onD adds two more fields to the PlaceNotes table.
Sub TestConnectionO ()
Dim myDB As ADODB.Connection
Set myDB = New ADODB.Connection
myDB.Open "f il e name=C:\MicroStation VBA\PlacePoints.udl"
myDB.Execute "Alter Table PlaceNotes " &
"Add NoteBy Char(SO), NoteDate Date "
myDB.Close
End Sub
TestConnecti onE adds a record to the PlaceNotes table.
Sub TestConnectionE ()
Di m myDB As ADODB.Connection
Set myDB = New ADODB . Connection
myDB.Open "file name=C:\MicroStation VBA\PlacePoints.udl "
myDB.Execute "Insert Into PlaceNotes " &
"(PlaceID. Note8y, NoteOate) VALUES " &
" (1, ' JKW' , '" & Now & ''')"
myDB . Close
End Sub
TestConnecti onF creates an additional field in PlaceNotes.
I Connections, Recordsets, and More I 721
Sub TestConnectionF( )
Dim myDB As ADODB . Connection
Set myDB = New ADODB .C onnect i on
myJB.Oper "file name=C : \~icroStation VBA\P l acePoints.Jcl"
myDB.E xecute "Alter Table Place Notes Add TheNote Memo "
myDB . Cl ose
En d Sub
TestConnect i onG updates all records in PlaceNotes where the NoteBy
field is 'JKW' by setting the "TheNote" field value to 'Reviewed'.
Sub TestConnectionG ()
Dim myDB As ADO DB.C onnect io n
Set myD B = New ADODB.Connection
myDB.Open "f il e name=C : \MicroStation VBA\PlacePoints.udl"
myDB .E xecute "U pdate PlaceNotes Set TheNote = 'Reviewed' " &
" Where NoteBy = ' JKW '"
myDB.Close
End Sub
This chapter is not meant to be a comprehensive tutorial on SQL
(Structured Query Language). It is good, however, to introduce some of
the functionality available to us by using standard SQL statements in an
Execute statement with the Connection Object.
Opening a Connection is time-consuming. Of course, it doesn't take
weeks, days, hours, or minutes. But it can take a second or two. If we
open and close a Connection to a database every time we want to work
with it, we will experience a performance hit. In some instances, we may
want to open a Connection once and keep it open until the application is
terminated. We can look at the Connection's State property to determine
whether it is open or closed.
Sub TestConnectionH ()
Dim myDB As ADODB .Conn ection
Set myDB = New ADODB.Connectio n
myDB.Open "file name=C : \MicroStation VBA \ Pl acePoints . udl "
Se le ct Case myDB.State
Case adStateClosed
MsgBox "Connect i on is Closed ."
Case adStateConnecting
MsgBox "Connection is Connecting. "
Case adStateExecuting
722 I Chapter 35: Working With Databases (ActiveX Data Objects) I
Msg Box "Con necti on is Exe cutin g. "
Cas e ad St at eFe t ch i ng
MsgBox "Connection is Fetching."
Case adStateOpen
MsgBox "C onnection is Open ."
End Select
myDB.Close
End Sub
Test Con nect ion H opens a Connection and then looks at each of the
possible States by using a Sel ect Case statement.
In Tes tCo nnec ti onJ, we are looking at a real-world example of how we
would use the State property. We first look at the variable myDB (which
should have been declared in the General Declarations area of the Code
Module or User Form) to see if it is closed. If it is closed, we open it by
using a UDL file.
Sub TestConnectionJ ()
If myDB.State = adStateClosed Th en
myDB.Open "fil e name=C:\MicroStation VBA\PlacePoints.udl"
End If
MsgBox "U se the Connectio n Object Here"
End Sub
It should be noted here that in Tes tConnect i onJ we are not declaring the
variable myDB or setting it to a New ADODB.Connection. We are
simply checking to see if it is closed. If so, we open it. In order for this
procedure to work correctly, the variable myDB must be declared in
such a way that it is available to this procedure (Public in a Code
Module or in the General Declarations area of the module in which this
procedure is located) and instantiated (set to as a New
ADODB.Connection). For example,
Sub TestConnectionK ()
Dim myDB As ADODB . Connection
Set myDB = New ADODB . Connection
I Connections, Recordsets, and More I 723
When we use a UDL file, the Connection String reflects the settings of
the UDL file. Although we have been depending on the UDL file, it is
possible to open a database and work with it without the use of a UDL
file by providing the ConnectionString when we Open the Connection.
Recordsets
The Connection Object is used to 'connect' with the database. The
Recordset is used to 'connect' with the Records in the database.
Sub TestRecordsetA ()
Dim myDB As ADO DB.Co nnec ti on
Dim myRS As New Recordset
Set myDB = Ne w ADO DB . Connect i on
myDB.Open "file name=C:\MicroStation VBA\ PlaceP oints.udl"
myRS.Open "Select * from Points Where County = ' Ventura '", _
myDB, adOpenDynamic, adLockOptimistic
Whi l e myRS.EOF = False
Debug.Print myRS("Des cr iption")
myRS. Move Next
We nd
my RS.Close
myDB . Cl ose
End Sub
TJindmill Canyon
TJomens Imp~o v ement Club of Hueneme
TJood Canyon
TJood C~eek P a~k
TJood Ranch 1027 Dam
TJood Ranch Golf Club
TJoo d Ranch Rese~voi~
TJoods ide Line ar P a ~k
TJoods ide Pa~k
TJo~ld Unive~sity
Xabaagua (histo~ical )
Xocotoc (histor i cal)
Verba Buena Beach
Verba Buena School
~]i
Ypuc (historical)
v;:
L?:;!-
In our first example, we use the Recordset Object to return all fields in
all records where the field 'County' has a value of 'Ventura'. Even though
we are getting all fields (by using the asterisk (*) in the SQL Select
statement), we only display the Description of each record in the
Immediate Window.
We will cover SQL statements later in this chapter. For now, we are going
to keep our attention on the Recordset Object.
In the procedure TestRecordsetA we can see that we use a Whi 1e ... Wend
statement and we look at the EOF (End of File) property. As long as the
I Connections, Recordsets, and More I 725
Sub TestRecordsetB ( )
Dim myDB As ADODB.Connection
Dim myRS As New Recordset
Set myDB = New ADODB.Connection
myDB . Open "f ile name=C:\MicroStation VBA\PlacePoints.ud l "
myRS . Open "Se l ect * from Poin ts Where Co unt y = ' Vent ura '" , _
my DB, adO penFo rward Only, adLockReadOnly
MsgBox myRS.RecordCount
myRS . Close
myDB.Close
End Sub
The RecordCount can be a very useful property. When used with
'adOpenDynamic' and 'adOpenForwardOnly', it always returns a value
of - I, however. When we use 'adOpenKeyset' and 'adOpenStatic', the
Recordset Property gives us the number of records retrieved in the
Recordset. For example, when we run TestRecordsetB, we see a
RecordCount of -1 no matter how many records we have retrieved due
to the Cursor Type specified in the Open statement of the Recordset.
Sub TestRecordsetC ()
Di m myDB As ADODB.Connection
Dim myRS As New Recordset
Set myDB = New ADODB.Connection
myDB.Open "file name=C: \ MicroStation VBA \ Pla ceP oi nts.ud l "
myRS.Open "Select * from Points Where County = ' Ventura '", _
myDB, adOpenStatic, adLockReadO nly
MsgBox myRS.RecordCount
myRS . Close
myDB . Close
End Sub
TestRecordsetC displays a RecordCount of2253.
I Connections, Recordsets, and More I 727
Sub TestRecordsetD ()
Dim myDB As ADO DB.C onnec t io n
Dim myRS As New Recordset
Set myDB = New ADODB.Connection
myDB.Open "file name =C: \MicroStation VBA\PlacePoints.udl "
myRS . Open uSe ect * from Points Where County = ' Ventura '", _
myDB, adOpen Dy nami c , adLo ckOpt i mi st i c
Wh il e myR S. EO F = Fal se
Debug.Print myRS( "Descr i ption " )
my RS. MoveNext
Wend
myRS.MoveFir st
Wh i l e myRS . EOF = False
Debug . Pr int myR S( "CellName" )
myRS.MoveNext
Wend
myRS.C l ose
myDB . Close
End Sub
Te st Recordset Duses the MoveF i rst method of the Recordset Object. This
allows us to begin at the top of the Recordset and look through the
records again, possibly looking for different information.
Sub TestRecordsetE ()
Dim myDB As ADODB.Connection
Dim myRS As New Recordse t
Set myDB = New ADODB.Connection
728 I Chapter 35: Working With Databases (ActiveX Data Objects) I
myDB . Open "file name=C : \MicroStation VBA\PlacePoints.udl "
myRS.Open "Select * from Points Where County = 'Ve ntura ' " &
"Orde r by CellNa~e ". myDB . adOpenDyran i c . adLockOptimist i c
myRS. Fi nd "CellName = 'Li on Canyon ' "
While myRS( "CellName " ) = "Lio n Canyon "
Debug . Print "Lion Canyon: " & myRS ( "Oes cription")
myRS .M ov eN ext
Wend
myRS . MoveF ir st
my RS. Fi nd "Ce l lName = ' Oxnard '"
While myRS( "C ellN ame " ) = "Oxnard "
Debug.Print "Oxnard: " & myRS( "D escription " )
myRS.MoveNext
Wend
myRS.MoveFirst
myRS.Find "Ce l lN ame = 'Fi llmore '"
Whil e myRS( "CellN ame " ) = "F i ll more "
Debug.P rin t "F i l lmore : " & myRSC "D escr i pt i on " )
myRS .M ove Next
Wend
myRS.Cl ose
myDB.Close
End Sub
In this example, we are only looking for records where the County =
'Ventura'. We use "Order by CellName" so the Recordset is 'sorted' by the
CellName field. Then we use the Fi nd method to find the first record
where the CellName is 'Lion Canyon'. After looking at each 'Lion
Canyon' Cell, we move on to looking for the first 'Oxnard' cell. And then
we do the same with 'Fillmore'.
Sub TestRecordsetF ()
Dim myDB As ADODB.Connection
Dim myRS As New Reco rdset
Set myDB = New ADODB . Connec t ion
myDB.Open "file name=C: \ Mic r oStation VBA \ PlacePoin t s.udl "
myRS . Open "Select Description , Ce l lName fr om Point s " & _
I Connections, Recordsets, and More I 729
myRS.Update
myRS.Close
myDB . Close
End Sub
Sub TestRecordsetJ()
Dim myDB As ADODB.Connection
Dim myRS As New Recordset
Set myDB = New ADODB.Connection
myDB . Open "file name=C:\MicroStation VBA\PlacePo ints .udl "
myRS.Open "Select * from PlaceNotes Where Pl aceI D = 1", _
myDB , ad Ope nDynam i c, ad LockO pt i mis tic
Whil e myRS. EOF = Fa lse
my RS( " P1 ace I D" ) = 14
myRS.Upda t e
myRS.M oveNe xt
Wend
my RS. Cl ose
myDB . Cl ose
End Sub
In Tes t Reco rd se tH, we add a new record to the table. In Test Recordse tJ,
we query the database and change the PlaceID value in each record
retrieved by the SQL statement. In both examples, we use the Update
method to apply the field values to the database.
SQL ESSENTIALS
Now that we have discussed attaching to databases by using the
Connection Object and the data inside the database by using the
Recordset Object, let's begin looking into the SQL statements that can be
I SQL Essentials I 731
The first Form we create is shown above. When the Form loads, we need
to query the database for all distinct State values. These values will be
added to the Sta te ComboBox.
Select Statement
The Select statement is the basis for many of SQL statements we will use.
It allows us to specify which fields we want to retrieve, which tables the
fields come from, how to order the records, how to group the fields, etc.
To get the distinct States in the Points table, we use:
Where
When we use the 'Where' statement, we begin providing the criteria
specifying which records we want to retrieve. In this example, we want
only records Where the State field is equal to the selected State in the
cmbState ComboBox. Since the State field is a String (Text), we use the
Apostrophe C) to begin and end the value.
Order By
The Order By statement allows us to specify how we want to sort the
Recordset's records. Multiple fields can be specified. We use ''ASC'' for
Ascending and "DESC" for a Descending sort.
cmbCoun t y . Clear
cmbPointType.Clear
lstDesc r iption . Clear
I SQL Essentials I 733
myDB. Open "fil e name=C: \ Micro Sta tio n VBA\ Pla ce Point s .u dl "
myRS . Open "Sel ect Dis t inct Coun t y fro m Poin ts Wh ere Sta te = " & _
"'" & cmbState . Tex t & "' Order by County ASC ", myDB
While myRS.EOF = False
cmbCounty.Addlte~ myRS( "County " )
myRS . MoveNext
Wend
myRS .Cl os e
my DB .C l os e
End Sub
OK, now when the user clicks a State, the Counties in the database show
up in the frmCounty ComboBox. When the user clicks on a County,
what should happen? Let's populate the cmbPointType Combo Box
with only those Point Types that appear in records with the selected
State and the selected County.
cmbPo in t Type.Clear
l stDescr i pt i on . Clear
myDB.Open "file name=C : \MicroStation VBA\PlacePoints.udl "
myRS .O pen "Selec t Distinct PointType from Points Whe r e State = " &
"'" & cmbState . Tex t & "' and" &
"County = '" & cmbCounty .T ext & "&
"Order by Poi nt Type ASC " , myDB
While my RS.EOF = Fal se
cmbPo i nt Type.Addltem myRS( "PointType " )
myRS. Move Next
Wend
myRS . Cl ose
myDB . Cl ose
End Sub
When the user clicks on the PointType ComboBox, we see all the
Descriptions that match all of the selected criteria in the ComboBoxes.
We place the UniqueID in the second column of the Listbox (but hide
the column so it is not visible to the end user).
734 I Chapter 35: Working With Databases (ActiveX Data Objects) I
Priva t e Sub cmbPointType_Click()
Di m myDB As New ADOD B.C onn ecti on
Dim myRS As New ADODB.Recordset
lstDescription.Clear
myDB . Open "fi l e name =C:\MicroStation VBA\P l acePoints . udl "
myRS . Open "Select Description . UniqueID f r om Points Where State " &
"'" & cm bSt at e .Tex t & "' and" &
"Cou nty = '" & cmbCo unty.T ext & " ' " &
"and PointType = '" & cmbPointType . Text & '" " &
"Order by Des c ri ption ASC ", myDB
While myRS. EOF = Fal se
lstDescr i pti on . Add It em myRS( "D es cr i pt i on" )
l stD esc rip t i on .L i st (lst De sc r i ption.Li s tC ount - 1 , 1)
my RS( " Un i que I D" )
myRS .M oveNex t
We nd
myRS. Cl ose
myDB .Cl ose
End Sub
All of the above code forms the framework for allowing the user to
select Places from the database.
.. .
. ,' ,
...
( .... •...............
OK
::: : ::: :':::::: : ::"::.
When the user clicks the OK button, the following code is executed:
En d If
Channel
It em
Item Child
We will use a Recordset for the Channel and the Item and will print the
Title, Link, and Description of each Item in the Immediate Window to
get things started.
Sub ReadRSSAC)
Dim MyDB As New ADODB.Connection
Dim MyRS As New ADODB.Recordset
Dim ChannelRS As New ADODB.Recordset
Di m ItemRS As New ADODB.Recordset
Ring-a-Ding-Ding, Baby
http://bloq. wire d. com/.ex/
Setting the proper mood wi th YOUl: ring tone . <strong>P Ius : </scrong> "Te!edildonic conception" rears its c
Tickr end Slickr Animate Flickx:
http://blog. wired. com/monkeybi te./
Nelil' apps bring scrolling images to desktops. <strong>Plus:</strong> tJhat makes Web 2.0 tick? From the Wit:
The POT.Je r 0 f the SlUl
http://blog . wired. com/gadget./
Foldable solar batter cha.rger pucs life into every gadget in your 8t:senal. <scrong> Plus: </str onq> South 1<
Japan Grows a Beard
http://TNWfiJ . wired . com/netJs/colu.mns/O, 70013-0 . heml ?tiJ=J::S3. index
As Japan's population ages, its numbers are shrinking. Young and old shun a fast-paced life style for a
Devious Tactic Snags Phone Data
h ttp ://www.wired.com/news/ technology /0,70027-0 . htJnl ?tw=r ••. index
VendoI:3 impet:30nate speech-impait:ed customers in hundt:ed3 of thousands of fraudulent customet:-service cal ,-..
t~~j
,}11
When the selected item is double-clicked we use the Shell Execute API
command to open the default browser on the system and the selected
story appears.
Here is the code:
Sub TestSchemaA()
Dim myDB As New ADODB.Connection
Dim myRS As New ADODB.Recordset
myDB . Open "file name=C:\MicroStation VBA\PlacePoints . udl"
Set myRS = myDB.OpenSchema(adSchemaColumns)
While myRS . EOF = False
Debug.Print myRS("TABLE_NAME") & "I" & _
myRS( "COLUMN_NAME " ) & "I" &
myRS( "IS_NULLABLE " ) & " I " &_
myRS( "DATA_TYPE " ) & " I " & _
myRS( "CHARACTER_MAXIMUM_LENGTH " )
myRS . MoveNext
Wend
End Sub
We still use a Connection Object and a Recordset Object. We still open
the database. But after it is open, we use the "OpenSchema" method of
the Connection Object. When we get the "adSchemaColumns", each
record returned has a number of different fields. Among them are
TABLE_NAME, COLUMN_NAME, IS_NULLABLE, DATA_TYPE,
and CHARACTER_MAXIMUM_LENGTH. These fields are important
so that we can understand the structure of each Field and Table
contained in the specified Database (specified in the UDL file, that is).
746 I Chapter 35: Working With Databases (Active X Data Objects) I
The values of each of these fields are printed to the Immediate Window.
The Immediate Window does not store an unlimited number of lines in
it. So, at times it makes perfect sense to write the values to a Text File.
OK Cancel Help
Even though the Jet driver is typically used for connecting to Microsoft
Access databases, we can use it to connect to Excel.
In the Connection tab, we need to browse for the Excel file. By default,
the Browse button's dialog box looks for Microsoft Access Databases
(.mdb). We can select the "*.*" option in the "Piles of type" combo box
and then select the Excel (.xls) file.
File name:
Files of type:
Itowerdat.xls
!AIIFiles ["")
~I Cancel .
//
750 I Chapter 35: Working With Databases (Acti veX Data Objects) I
I
Provider Connection Advanced All I
Specify the following to connect to Access data:
1. Select or enter a database name:
IC: \Microstation VBA \towerdat. xis
2. Enter information to log on to the database:
User name: lAd min
Patsword: r ' 1- - - - - - - - - - -
Since working with Excel is new territory, how can we tell what we have
to work with? Let's modify our previous "OpenSchema" procedures to
work with the Excel.udl file.
Sub TestSchemaC ()
Dim myDB As New ADODB . Con nection
Di m myR S As New AOOD B.Reco rds et
Dim FFile As Long
myDB . Open "fi l e name=C : \MicroStation VBA\Exce l .udl "
Set myRS = myDB . OpenSchema(adSchemaColumns)
FF i le = FreeF i le
Open "C:\ObSchema . txt" For Output As #FFile
While myRS.EOF = False
Print #FFi l e , myRS( "TABLE_NAME " ) & "I " &
myRS( "COLUMN_NAME " ) & "I" &
myRS( " IS_N ULLABLE " ) & " I" & _
myRS( "DATA_TYPE " ) & " I" & _
myRS( "CHARACTER_MAXIMUM_LENGTH " )
myRS.MoveNext
Wend
Close #FFile
End Sub
When we run this
procedure, a new file is
File Edit Format View Help
created that contains the CABLEYUN I Fli True 15 I
CABLEYUNIF21Trueisi
Database Schema of the CABLEYUNIF31Trueisi
DATA...RANGEl xy=1832S, 22791 ,S1 4 1Tr ue l13 0 1255
TOWERDAT$I Cable YITruelsl
Excel file. Let's open it and TOWERDAT$lcable ZITr uelsl
TOWERDAT$I Cable x lTr uelsl
take a look at it. It is TOWERDAT$IDATASETI Tr ueI1301 2SS
TOWERDAT$l xI Truelsl
TOWER DAT$IYITrUelsl
named DbSchema. txt. TOWERDAT$lzITr ueISI
752 I Chapter 35: Working With Databases (ActiveX Data Objects) I
We can see a Table named "TOWERDAT$". That's interesting. When we
look at the Excel file, we find a Worksheet named "TOWERDAT". This
looks promising. Let's see what we can do with "TOWERDAT$".
Sub TestDBExcelA ()
Di m myDB As Ne w ADODB. Co nnec ti on
Di m myR S As New ADO DB .Rec ords et
Dim myField As Fie l d
my DB.Open "file name=C:\MicroStat i on VBA\Excel.udl "
myRS.Open "[TOWERD ATS]", myDB, _
adOpenDynamic, adLockOptimistic
While myRS.EOF = False
For Each myField In myRS.Fields
Debug . Print myField.Name & "I" & myField.Value
Next
Debu g. Print vbCr
Xl18325
myRS .M oveNext YI 22 791
ZI514
Wend DATASET lxy=1 832 5, 22 791,514
Cable x l1 8290
End Sub Cabl e Y12292 9
Cabl e Zl8 94
REVIEW
ActiveX Data Objects gives us tools to work with Data. At times this
Data is stored in Databases. This Data can be 'stored' on the Internet in
RSS files. This data can even be stored in a Microsoft Excel file.
Independent of where the data is, ActiveX Data Obj ects can be used to
retrieve the data. The process of connecting to data sources is simplified
greatly by the use of UDL files. Once connected, the Connection and
Recordset Objects can be used to retrieve, manipulate, edit, and add
data.
754 I Chapter 35: Working With Databases (ActiveX Data Objects) I
36 MicroStation Leveraging
Mathcad via VBA
Any time a company opens its product for customization, the consumer
wins. Mathcad is one such product. Mathcad worksheets can be used to
perform calculations and then can 'hand off' the information to
MicroStation through the use of VBA. Of course, Mathcad is not a
Bentley product. And the inclusion of Mathcad in this book should not
be considered an endorsement in any way. The same should be said of
Microsoft Excel and any other third-party products discussed in this
book. That having been said, Mathcad like Excel can be customized and
channels of communication can be opened between Mathcad and
MicroStation resulting in an integrated solution.
In this chapter:
[B A Brief Introduction to Mathcad
755
756 I Chapter 36: MicroStation Leveraging Mathcad via VBA I
...
~vailable References:
---===---_._----_._-
r OK j
[t] r~athcad 12 Automation API
.., ••
C Mathcad Private Automation Type library 0d i I Cancel )
C Mathcad XSL T Extensions library
[J MAXComponents 1.0 Type library !l.rowse ...
[J Mead 1.0 Type library
[J McAfee Virus Scan API 1.0 Type library
C McAfee .com Virus Map Typelib
[J McAfee. com Virus Scan Control Type library Priority [
C MCLauncher 1.0 Type library . tlelp
C MediaPlayer 1.0 Type library ~ '---="-'----J
C MerchantCard 13.0 Type library
C Messenger API Type library
C Messenger Extensions Type Library Vi
rl Mp,<;<;p.nnp.r PrivAtA TvnA I ihr i'lrv t,.~j
<=;i""
l:~=--
='k=:_=
~r=·U==
_·':'
- =.. . ,=-·=
-JI, --______"']j-
, Mathcad 12 Automation API .... .. ..
Once a Reference has been added, we can use the VBA Object Browser
to 'browse' the Mathcad Object Model.
Class AlllllicatiQII
Member of M"thc""
Malhcad Application Object
-~ ,:;t<;\!"~~..,.~>;..."",,,,"t;. >·'.N ..... __ ~ '" 'Y ,""~;<":""~ ~"'"t-" ;;>;~... ~"" _ h~Y;~W ",-w~ ,,~~ _ "- ~-<1"""'C'\.' .":"<."'·'<~~m""'---~-;;;r;-~I'i!>- >:'<i~
rUi!} /'Aat~cadJfi[Sampl!cJ,,,l!I!!,:dl~~~~~c::.ll:1,~~~;t,~~
. .~._B.!: __~~i~ _c~e_I'I _ ~ns=~_~_. . .~~r~~~.._ r.~~ls__ ...~~m~~I~~~_ .....~~~.~?I'I _ ~=!~ . _. . . _c_...._ . . ._.. . . c. c. .
j DT~1iiI ~~~ '"'{,~ ~ .:'") ,,, ••-;- @D= ~ ~r:
jl Narmal v ;IAr;al vl 12 vJL B I !! r~2:E
j Iii 4' [;;;] x= J~ <~ r~ ajJ ~ IH~§~_
e _______.
Here is a po rtion
of t he RoughLength:= 18ft + Sin
Worksheet.
JambShim := ~ in
2
StrikeShim := ~in
2
MaxLength := 300em
:MinLength := 50 em
Sub TestMathcadA ( )
Dim my MCA As Mat hcad.App lic atio n
Dim myMCW As Mathcad , Worksheet
Set my MCA GetObject( , "Mathcad . Application " )
Set myMCW = myMCA.ActiveWorksheet
End Sub
We saw the Application and ActiveWorksheet objects in the Object
Browser. If we run the macro Tes tMat hca dA we will find that the code
executes but we are not at the point where we are getting the value of the
RoughLength variable in Mathcad.
I Adding a Refe rence and using the Object Browser I 759
g[~~~t~~:::~l~tadaia
~ Works heets
GetValue •
,v
Sub TestMathcadA ( )
Di m myMCA As Mat hc ad . App l i cat ion
Di m myMC W As Mat hcad .W or ksheet
Dim myMCV As Mathcad . Value
Set myMCA GetObj ect ( . "Mathcad . Application " )
Set my MCW = my MCA.Ac t ive Worksheet
Se t myMCV = myM CW. GetValue("RoughLength")
MsgBox myMCV.AsStr i ng & vbCr & myMCV.Type
End Sub
5.6134
Now, in addition to connecting to the Mathcad Application and the
Numeric ActiveWorksheet, we are getting a Value Object based on the parameter
RoughLength and displaying its "As String" and "Type" properties in a
MessageBox.
760 I Chapte r 36: MicroStation Leverag ing Mathcad via VBA I
r CE If C I
we were shown a value of 5.6134. Why
is this? It must be a units issue. Let's try
~0 00 0B dividing 5.6134 by 221 inches and see
800000 what we get.
GD [Q Q C2JOG When we see the magic number 0.0254
B0GDGJD we know we are dealing with an inches
to meters conversion issue.
So, when we look at the Object Browser at the function GetValue, we see
that it returns an Object. When we use a variable declared as a "Value"
Object, we can get the ''AsString'' and "Type" properties of the "Value"
object. Is there more we can do here?
When we add a watch to the variable myMCV, we can see the other
properties belonging to the Value Object.
Imag Double
Integer 6 Long
Real 5,6134 Double
Type "Numeric" string
The variable myMCV is declared as a "Value" but we can see here that we
are actually being returned a "NumericValue" (look in the Type column)
Object. Let's change our code a little by declaring the variable myMCV as
a "NumericValue" Object and see what happens.
S ub Te stHathc a dB ()
Dim myHCA As Hathc a d.Application
Dim myHChl As Hathc ad.hlo rkshe e t
Dim myl-ICV As Hathc ad . NurnericValue
Set my~ICA = GetOb j ect ( , "Hathcad . Applic a t ion" )
Set myl-IChl = myHCA . Ac tivehlorksheet
Set myl1CV = myl1ClJ. GetVal ue ("RoughLength")
msgbox mymcv.
End Sub i1£' iA~i3jiin.i :
i1£' Imag
i1£' Integer
r1i' Real
i1£' Type
I Adding a Reference and using the Object Browser I 761
Sub TestMathcadB()
Dim myMCA As Mathcad.Application
Dim myMCW As Mathcad.Worksheet
Dim myMCV As Mathcad.NumericValue
5. 6 134
a Set myMCA GetObj ect ( . "Mathcad.Application")
6
5 .6134 Set myMCW = myMCA.ActiveWorksheet
Numeric
Set myMCV = myMCW.GetValue( "RoughLength " )
i-UOK·· ---]1 MsgBox myMCV.AsStr i ng & vbCr & _
myMCV.lmag & vbCr & _
myMCV. l nteger & vbCr & _
myMCV.Real & vbC r &
my MCV .Type
End Sub
Now we are getting somewhere. In this MessageBox, we can see the
''As String" and "Real" property values of 5.6134, an "Integer" property
value of 6, and a "Type" property of "Numeric". Let's try making one
additional change to our code.
Sub TestMathcadC ( )
Di m myMCA As Mathcad . Applicat i on
Dim myMCW As Mathcad . Works heet
Dim myMC V As Mat hcad.S t r in gVal ue
Set myMCA GetObject( . "Mathcad.Application")
Set myMCW = myMCA.ActiveWorksheet
Set myMCV = myMCW.GetValue("RoughLength " )
MsgBox myMCV . AsStr i ng & vbCr & _
myMCV.lmag & vbCr & _
myMCV.lnteger & vbCr & _
myMCV . Real & vbCr &
myMCV . Type
End Sub
762 I Chapter 36: MicroStation Leveraging Mathcad via VBA I
Instead of declaring myM CV as a "NumericValue" we declare it as a
"StringValue". What happens?
~~,.;'~~<r.":;<~~l~~~'Cf~.,.~ ";'""....,..~"'~,- ,o;m7-=""....,.. ... '" ...
~ ~'!'-:~w~~=.<;:'"tJ..~~
Type mismatch
Sub TestMathcadD ()
Dim myMCA As Mathcad . Appl i cation
Dim myMC W As Mathcad . Wor ks heet
Di m myMCV As Mathcad. Valu e
Di m myMCNV As Mathcad. Numer i cVal ue
Dim myMCSV As Mathcad.StringValue
Set myMCA GetObject(, "Mathcad.Application")
Set myMCW = myMCA . ActiveWorksheet
Set myMCV = myMC W. GetValue("RoughLength")
Select Case myMCV.Type
Case "Numeric"
Set myMCNV = myMCV
MsgBox myMCNV.AsString & vbCr &
myMCNV.lmag & vbCr & _
myMCNV.lnteger & vbCr & _
myMCNV.Real & vbCr &
myMCNV.Type
Case "String"
Set myMCSV = myMCV
MsgBox myMCSV.AsString & vbCr &
myMCSV.Type & vbCr & _
I Basic Macros that Communicate With Mathcad I 763
myMCSV . Value
End Select
End Sub
We begin by usmg a generic "Value" object. Then we look at the
Value.Type property. If it IS "Numeric", we use a
"Mathcad.NumericValue" object. If it is a "String", we use a
"Mathcad.StringValue" object.
Sub TestMathcadE()
Dim myMCA As Mathca d. App l i catio n
Dim myM CW As Ma t hcad . Workshee t
Di m myMCV As Ma thc ad.V alue
Dim myMCNV As Mat hcad.Nu mericValue
Set myMCA GetO bject(, "Math cad.Application")
Set myMCW = my MCA . Act i ve Wor ksh eet
Set myMCV = myMCW.GetValue("RoughLength")
Set myMCNV = myMCV
MsgBox "Roug h Length: " & myMCNV. Rea 1 / 0 .0254 & " Inches."
End Sub
TestMathcadE displays the RoughLength variable in a MessageBox after
converting it to Inches.
Rough Length: 221 Inches.
Our previous examples dealt with pulling information from Mathcad.
C OK-~
Let's try changing a variable's value, recalculating the Worksheet, and
then pulling a value.
Sub TestMathcadF()
Dim myMCA As Mathcad.Application
Dim myMCW As Mathcad.Worksheet
764 I Chapter 36: MicroStation Leverag ing Mathcad via VBA I
Dim myMCNV As Mathcad.NumericValue
Set myMCA = GetObject(, "Mathcad.Applicatio n" )
Set myMCW = myMCA.ActiveWorksheet
myMCW.SetValue "JambShim", 0.375 * 0.0254
myMCW.Recalculate
Set myMCNV = myMCW.GetValue( " FinishLength " )
MsgBox "Fin ish Le ngth: " & myMC NV.Re al / 0 . 0254
End Sub
When this macro runs, we see a
MessageBox with a value in it
but the calculation seems to be
off. When we look at the
Mathcad Worksheet we can see that the JambShim variable has a
problem with the value we attempted to give it.
Why is this happening? Values assigned to Variables through ActiveX
Automation are calculated prior to those defined in the Mathcad
Worksheet. So, when we attempted to Set a Value for JambShim, in
addition to the value shown in the Worksheet, Mathcad attempted to
use a value from the SetValue call and this caused a problem.
So, we know why the error is occurring. How do we fix it? One solution
is to remove the "1/2 in" value assigned to the JambShim variable so the
duplicate value assignment is no longer taking place. And instead of
assigning JambShim a value of "0.375 )\- 0.0254", we are going to give it a
value of "3/8". Next, we are going to change the formula for the
FinishLength variable to 'convert' the JambShim value to Feet and
Inches. To best illustrate this change, we will look at the code and then at
the Worksheet.
Sub TestMathcadF2()
Dim myMCA As Mathcad.Application
Dim myMCW As Mathcad.IMathcadWorksheet2
Dim myMCNV As Mathcad.NumericValue
Set myMCA = GetObject(, "Mathcad.Application")
Set myMCW = myMCA.ActiveWorksheet
myMCW.SetValue "JambShim", "3/8"
myMCW.Recalcula t e
Set myMCNV = myMCW.GetValue("FinishLength")
MsgBox "Finish Length: " & myMCNV.Real / 0.0254
End Sub
I Basic Macros that Communicate With Mathcad I 765
JambShim:= I
StrikeShim := ~in
2
MaxLength := 300cm
:MinLength := SOcm
Sub TestMathcadG ( )
Di m myMCA As Math ca d .A ppli cat i on
Dim myMCW As Mathcad.Worksheet
Dim myMCR As Mathcad.Region
Set myMCA = GetObj ect ( . "Mathcad. Appl i cat ion " )
Set myMC W= myMCA.ActiveWorksheet
MsgBox myMCW.Regions.Count
For Each myMCR In myMCW.Regions
MsgBox myMCR .Typ e
Next
End Sub
The Region.Type property is an Enumeration named "MCRegionType".
Here are their values:
mcBitmapRegion 2
mcMathRegi on = 1
766 I Chapter 36: MicroStation Leveraging Mathcad via VBA I
mcMetaf ileRegion 3
mcOLERegion = 4
mcTextReg i on = 0
In the "Sample 1" Worksheet, we see a lot of "mcMathRegion" Regions.
An "mcMathRegion" is a Region that involves numeric calculations and
variable assignments. So, even if a variable is holding a String value, it
qualifies as a MathRegion.
IMathcadWorksheets2
Here are the Properties for the IMathcadRegion2 Object. One of them is
the "Mathlnterface" property. When we click on "MathInterface" in the
Classes list, we see the following:
--.--------.-------J
[_._---
Moth cad
-
v
-
C ___________ ~.I
Cla sses Memb ers of 'Math Interface'
~ IM ath ca dRe gion2 ~ , ~ ErrorMsg
~ IM athca dWorks heet2 ~ HasError
~ IMathcadWorkslleets 2 ~ UnitsXML
li!IJ IMetadata ~ XML
~ Mathcad Ol d
li!IJ
li!IJMatrixValue
rfjl MCAppOptio n
Class Mathlntenace
Member at Mothcad
Mathcad Mathlntertace object
<ml : define xm l ns :ml= ''h ttp : //schemas . mat hsoft . com/math20 ' )
<ml :i d xml : space =" preserve ")RoughLength</ml : id>
<ml : apply>
<ml : pl us/)
<ml : apply>
768 I Chapter 36: MicroStation Leveraging Mathcad via VBA I
<m l :mu lt sty le = "auto -sele ct " l>
<ml :real font="O ">18</ml :real>
<m l : id xm l :space=" preserve ">ft</ml : i d>
</ ml:ap ply >
<ml :apply>
<ml : mult style= "auto-se l ect " l >
<ml : r ea l fo nt=" O">5</ ml : real>
<ml : i d xml : sp ace =" prese r ve ">i n</m l : i d>
</ml : apply>
</ml : apply>
</ml : def i ne>
This is the data that is associated with the RoughLength variable in our
Worksheet. Let's take a look at a few more:
We can see here that the calculation for the FinishLength variable in our
Worksheet is the RoughLength minus the Feet and Inch value of the
JambShim variable minus the StrikeShim.
Application
ActiveWindow Height Top
ActiveWorksheet Left Version
Application Name Vis ible
CloseAl1 Parent Width
Defa u ItFi lePath Path Windows
FullName Quit Worksheets
770 I Chapter 36: MicroStation Leveraging Mathcad via VBA I
In addition to the Application Object, Mathcad has an
IMathcadApplication2 Object. Creating additional Application-type
Objects is usually done to preserve compatibility with the older parts of
an Object Model while introducing new properties and methods. Of
note here are the Get 0pt ion Method, the HWN0 property (often used in
Windows API programming), and the SetOpt i on Method.
IMathcadApplication2
Active Height Top
ActiveWindow HWND Version
ActiveWorksheet Left Visible
Application Name Width
CloseA l1 Parent Windows
DefaultFilePath Path Worksheets
FullName Quit
GetOption SetOption
Overall - OutsideBuffer· 2
CaicuiateQuantity(Overall) :~ -------
HoleDia + MaxSpacing
QtyWidth := trunc(CaicuiateQuantity(Width)) + I
QtyHeight := trunc(CaicuiateQuantity(Height)) + I
Overall - OutsideBuffer· 2
ActualSpacing(Overall) :~ - HoleDia
QtyWidth
SpacingX1n :~ ActualSpacing(Width)
HoleDiain := HoleDia
OutsideBufferln :~ OutsideBuffer
Widthln: = Width
+
HeightIn :~ Height
Widthln ~ 17 in
H eightIn ~ 26 in
QtyWidth ~ 6
QtyHeight ~ 10
SpacingX1n~ 1.705 in
SpacingYIn ~ 3.205 Ul
H oleDiain ~ 0.472 in
OutsideBufferln ~ 1.969 in
<ml :defi ne xml ns :ml= '' http://schemas . mathsoft. com/math20 " >
<ml :id xm l :space=" preserve">Heightln</ml :id>
<ml : i d xml: space= " preserve " >Hei ght</ml : i d>
</ml : defi ne>
Sub DrawFromMathcad ()
Dim Al lEvals() As String
Dim PartWidth As Double
Dim PartHeight As Double
Dim OutsideBuffer As Double
Dim HoleDia As Double
Dim SpacingX As Double
Di m SpacingY As Double
Dim OtyX As Double
Dim OtyY As Double
Dim FilterReturn() As String
AllEvals = GetEvals
Point3dFromXY(O, 0), _
POi nt3dFr omXY( Width, 0))
Act i veModelRefere nc e . AddE l ement myL in e
Point3dFromXY(Width, 0 ) , _
Point3dFromXY(W i dth, Height) )
ActiveModelReference.AddElement myLine
Se t my Li ne CreateLineE l ement2(Nothing, _
=
Point3dFromXY(O, Height), _
Point3dFromXY(0, 0))
Ac t iveModelReference.AddElement myLine
o o o o o o
o o o o o o
o o o o o o
o o o o o o
o o o o o o
o o o o o o
o o o o o o
o o o o o o
o o o o o o
I Driving Mi croStation Geometry from Mathcad I 779
SpaeingXIn:= AetualSpaeing(Width.QtyWidUl)
o o o o o o
o o o o o o
o o o o o o
o o o o o o
o o o o o o
o o o o o o
o o o o o o
o o o o o o
o o o o o o
o o o o o o
2.0457
1.9685
The Buffer area looks right. But the spacing between the holes isn't
meeting our criteria. A review of the Formulas and Functions in
Mathcad shows us that the Ca lc ulate Quantity Function has one more
error in it. We need to calculate the quantity of items, not the number of
spaces. So, we will add 1 to the formula so we are retrieving the number
of items that fit in the space, instead of the number of spaces.
We fix the formula in Mathcad and run the macro from within
MicroStation's VBA environment and the plate is drawn again. Adding a
few dimensions to it shows us the result.
782 I Chapter 36: MicroStation Leveraging Mathcad via VBA I
1.626
o
1.9685
Now, it looks like the spacing between the holes is meeting our criteria
of "MaxSpacing = SOmm". Changing the Width, Height, Hole Diameter,
and OutsideBuffer in Mathcad and running the macro again should
yield similar results - a plate drawn in MicroStation with holes spaced
evenly (in the respective X and Y planes) and spaced within the
MaxSpacing rule.
REVIEW
Someone once said, "Give me a lever and I will move the World:' A
study of the effects of various types of levers shows that with a lever we
can move objects that would be impossible to move without the use of
the lever. Mathcad and other applications that allow us to communicate
with them through ActiveX Automation serve as levers. They allow us to
accomplish tasks previously error prone and time consuming with little
or no effort.
This chapter is by no means a comprehensive reference on the use of
Mathcad or its API. An entire book could be devoted to that topic. The
goal here is to introduce and demonstrate the ease with which we can
take engineering data and calculations from Mathcad and use them in
our design work within MicroStation.
37 Accessing Data from
External Applications
In this chapter:
[El ActiveX / COM Basics
[El References, Early Binding, and Late Binding
[El GetObject, SetObject, and 'New'
[El What does 'WithEvents' do for us?
[El When to run macros from within Excel and when to run them
from within MicroStation
[El Controlling MicroStation from within Excel
783
784 I Chapter 37: Accessin g Data from External Applications I
Available References : OK
Cancel
:~:j Microsoft Access 11.0 Object Libr ary
i::J Microsoft Active Server Pages Object Library
;::J ~licrosoftActive Server Pages Object Context Object Browse ...
[J Microsoft
[J Microsoft
[J ~licrosoft
ActiveMovie Control
ActiveX Data Objects (Multi-dimensional) 2.
ActiveX Data Objects 2.0 Library
-.!J
[J Microsoft ActiveX Data Objects 2 .1 Library Priority
i:J Microsoft ActiveX Data Objects 2.5 Library Help
[ J Microsoft ActiveX Data Objects 2.6 Library .. I
[J ~licrosoft ActiveX Data Objects 2.7 Library ~
[] Microsoft ActiveX Data Objects 2.8 Library
i::J Microsoft ActiveX Data Objects Recordset 2.7 Librar) -',
n Mirrn<nft ArtivAX Ph Inin ;~ l
~: ::;,'~- gL-~~~-,,] ,Lei
" .. ~, Type Libr ary ---------------------------------------------------- -------------- --------------------------- - ,
We have seen this before. Let's talk a little more about what we are
actually seeing.
786 I Chapter 37: Accessing Data from External App li cations I
1~
~- , 3-
co-
m _-dm-
i -------------~
--1 0-41---
1~ 1~5 ~ 1 ~2
IB 1~8 ~1~4
1r(::) 1031 B2052
IB 1 ~ B ~~
ifC:l 1037 fC:l appmgmt
Ii5!,':
.. ,
File name: I. Open
Files of type: IType Libraries ("olb;".tlb;". dtll Cancel
Help
In the above graphic, when we type 'myInet: (with a period after the
variable name), Intellisense does not show up to help us. If, however, we
declare my Inet as an "InternetExplorer", we have Intellisense to help us if
we have also added the correct Reference, which in this case is
"Microsoft Internet Controls".
Sub RunInte rnetExpl o rer()
Dim myInet As InternetExplore r
Set myInet = Cre a t e Object ( "Inte rnetE x pl o r e r.Ap pli c ation")
myIn e t.
NsgBo ~ Application
:. /
my In e ~ !~~:~f.~:~~:~:~~:::: ::::::::::::::::::::::::::~ ~ www.bentley.co m "
si t e. "
myIne @' Busy /"WWW.micros oft . com "
~lsgBo ··,~Cli entToWi ndow ebsite."
End Sub @' Container
~ Doc um ent I
"'~ ExecWB v
Sub ConnectToMicroStationA ()
Di m myMSAppCon As Mi croStat i onD GN.App li cat i onObjectConnector
Dim myMSApp As Mi croStat i onDGN.App li cation
Set myM SA ppCo n = Ge t Obje ct ( , _
"Mi croSta ti on DGN. Appl icati onObj ect Connecto r" )
Set myMSA pp = myMSApp Con .Ap pli cat ion
we will either see us.er interface,dgn, Index (2D - va DGN) - MlcroStation V8XM Edition (Seta)
something like thi s:
IL~:~::::§:~:::::~
~d tielp
Sub ConnectToMicroStationB ()
Dim myMSAppCon As MicroStationDGN.ApplicationObjectConnector
Dim myMSApp As MicroStationDGN.Application
Set myMSA ppCon = _
CreateObject("MicroStationDGN.ApplicationObjectConnector")
Set myMSApp = myMSAppCon.Application
myMSApp . Vi sib l e = True
Sub ConnectToMicroStationC ()
Di m myMSAppCon As New _
Mi croStat i onDGN . Appl i cationObjectConnector
Dim myMSApp As MicroStat i onDGN . Application
Se t myMSApp = myMSAppCon .Applicat i on
myMSApp . Vis i ble = True
Sub ConnectToMicroStationD ()
Dim myMSAppCon As MicroStationDGN . ApplicationObjectConnector
Dim myMSApp As MicroStationDGN.Application
Set myMSAppC on = New _
MicroStationDGN .A pplicationObjectConnector
Set myMSApp = myMSAppCon.Application
myMSApp . Visible = True
MsgBox myMSApp.Cap t i on
MsgBox myMSApp.Caption
Let's create a new Excel Workbook. We will then get into Excel's VBA
environment by clicking Tools> Macro> Visual Basic Editor.
Next, let's insert a new Module.
: E.~e !;.dit ~ew Insert FQ!mat Q.ebug Bun 10015 £l.dd-lns 'Wndow tlelp
,t~~ • Q I ~ ,\f1.~ MIl '-'1 r' I ~ .UJ 0 ~ I ~ @" W '~~ l @ I, Ln I, Coil I
VBAProject
f"l <5 Microsoft Excel Objects
:- Ii!) Sheetl (Sheet!)
. Ii!) Sheet2 (Sheet2)
,. Ii!) Sheet3 (Sheet3)
.. :[) ThisWorkbook
8 e':l ~Iodules
'... ~ Modulel
The VBA environment in Excel should look a lot like the VBA
environment in MicroStation. One thing that is different, however, is the
Project Window. "Microsoft Excel Objects" are available to us. What are
they? These Excel Objects allow us to write code directly into events
pertaining to specific Worksheets or the Workbook.
So, we have a Code Module inserted. And we want to write code that
communicates with MicroStation. What is our next step? We should add
a Reference to the "Bentley MicroStation DGN #.# Object Library".
With the Reference in place, it is time to write some simple code that
communicates with MicroStation.
Sub XLMSA()
Dim myMSAppCon As MicroStationDGN.ApplicationObjectConnector
Dim myMSApp As MicroStationDGN.Application
Dim myLevel As Level
Dim CurRow As Long
The Level number and Name are placed into Excel's "Sheetl".
N ow, instead of reading Levels from MicroStation's ActiveDesignFile we
are going to create Levels based on what is in Excel. Let's create a new
design file in MicroStation before we continue.
A 8 C
When we run XLMSB with the above data in Excel, we get new Levels
created in the new .dgn file. Here is the code:
Sub XLMSB ()
Dim myMSAppCon As MicroStationDGN.ApplicationObjectConnector
Dim myMSApp As MicroStationDGN.App l i cation
Di m myLevel As Level
Dim CurRow As Long
Cu rRow = 2
While Sh eet l .Ce lls(C urRow. 1) <> n n
Set myLevel = myMSApp.ActiveDesignFile.AddNewLevel _
(Sheetl.Cel;s(C urRow. 2))
myLevel.Number = Sheetl . Cells(CurRow . 1)
my Level .Descriptio~ = Sheetl.Cells(Cu r Row. 3)
CurRow = CurRow + 1
Wend
End Sub
After the above code is run, we can see the results in the Level Manager:
I 6- Name ,;;; , Number ! Description File Logical EJ
Default 0 Chapter 17_"" Master Do
Existing Terr ain 1 Existing Terr ain Level Chapter3?_"" Master Do
Building SiteTerrain 2 Building Site Terrain Level Chapter3?_"" Master Do
ExistingTerrainM esh 3 ExistingTerrainM esh Level Chapter3?_ "" Master Do
Frame Frame Level Chapter3?_" Master Do
Buil " iteMesh BuildingSiteMesh Level Chapter3?_ " Master Do
Formatting
'"
- Borders
- Chart r[f~~i~~;~j L .commands II Qptiona _ _ _ _ _ _ _ _ __
......
.....
Visual Basic
dose
Watch Window
-.-
Web
-
.- •.. WordArt
- "'-" -_.. .--- 2 Click the New button to begin
S;;ustomize. .. I\.
'\\
the steps to create a new toolbar I oolbar name:
in Microsoft Excel. .~oStation VBA
Ii· OK iJ I Cancel
3 Name it "MicroStation VBA"
and click 0 K.
And now for a warning: the new toolbar is very small because it
does not have any buttons or menu items in it.
4 N ext, change to the Commands tab and select "Macros" in the
Categories Listbox. This brings up two 'Commands' - "Custom
Menu Item" and "Custom Button".
I Contro lli ng MicroStation from wi thin Exce l I 799
5 Drag and drop "Custom Menu Item" into the new toolb ar we just
created.
v .~._..
.
I Close
Assign !:!yperlink
Assign Macro ...
800 I Chapter 37: Accessing Data from Externa l Applications I
7 The Name property specifies what the menu item will display. At
this point it is set to "Custom Menu Item". Let's change it to "&Get
DesignFile Levels':
8 Another right-click on the menu item allows us to "Assign Macro".
Macro name:
9 We can select a macro and click the OK button. This assigns the
selected macro to the button. From this point on, any time the
button is clicked, the macro XLMSA is run in Excel.
Now that we have renamed and assigned the Menu Item we can run
it after we close the Customize dialog box.
10 The macro we are going to run populates cells in Sheetl. Before we
proceed, let's delete the data in Sheetl. After we do this we can click
the Get DesignFile Levels button just to make sure everything works
correctly.
11 Now we are going to save the Excel file and close it. After the
workbook is closed we will begin a new workbook. Then we will
click the Get DesignFile Levels button again. What happens next
depends on your Security settings in Excel.
So, even if we close the Excel file in which the macro is written, when we
click the button that links to the macro, Excel opens the workbook so it
can run the macro. Ifwe 'Enable Macros' (if we are prompted to do so),
the macro is run and the Levels are entered. But where are they entered?
They are entered into the Book 1.xls file even though we may have had a
different workbook open when we clicked the button. Let's take another
look at the code that is running:
Sub XLMSC C)
Dim myMSAppCon As MicroStationDGN.ApplicationObjectConnector
Dim my MSApp As MicroStation DGN .Application
Dim my Level As Level
Dim CurRow As Long
1 Let's open Book 7.xls in Excel. Then save the file Book 7.xls as an
Excel Add-in. Let's use the filename MicroStationVBA Add-In.xla.
...~ 1!!bBatchProcessing
La Illbcd material
~ly Recent !l!b docs
Documents iifC:)Documents
trr~:il !il,:",", Fonts
J1 Iif$ fr om mark
I i!O PlcS
'." .':.\
Desktop
[.;.I.
II~
ia
~~~~e
VB6
Code
My Documents 'i
i
r~y Computer ' I
My Network
,~Fi;le~na~m~e~:~~~~@W§~
I rl l"" . ~*~~~j~m~i'
... ..... ~$~~a~mm~m~~~~
....... ..... ............
Places ! save as ~ype: Office Excel Add·In (*.xla)
add·Ins available:
ro.mmMllli . r-. ,.. ~.. OKi
!O Analysis ToolPak - VBA
10 Conditional Sum Wizard
iOEuro Currency Tools
I. Cancel I.
!O Getpricing
!O Internet Assistant VBA
iO Lookup Wizard
iO Solver Add·in
Analysis ToolPak
Provides functions and interfaces for financial and
scientific data analysis
804 I Chapter 37: Accessing Data from External Applications I
4 Let's browse to the new .:xla file we just created.
'I
My 'Computer I
7 Now, the Menu Item we added to our custom toolbar is still pointing
to Bookl.xls. We want it to run the macro in the Add-In file we just
created. Let's go back to the Assign Macro dialog by right-clicking
on the Menu Item, selecting Customize, right-clicking on the Menu
Item again, and selecting Assign Macro.
I Review I 805
i~----~--~ ~-i ~
Bookl .xls . Wewantto
run the macro in the
Add-In. But macros
in Add-Ins don't
I E,j:t
available macros, so i
L._.______ _1
I
just type the macro A _ _ . _ . _ _ _ _ • _ _ _ _ _ _ _ • _ _ _ _ _ _ ••
REVIEW
Nearly all of the code that has been written to this point in this book can
be run from within Excel's or MicroStation's VBA environment. When
we develop in Excel, we add a Reference to the "Bentley MicroStation
DGN #.# Object Library". When we develop in MicroStation and wish to
work with Excel, we add a Reference to "Microsoft Excel #.# Object
Library". We use GetObj ect to get existing instances of the application we
wish to attach to and CreateObject or New if we want to create a new
instance of the application with which we want to work.
806 I Chapter 37: Accessing Data from External Applications I
38 Writing VB6
Applications
We have written a lot of code in VBA. Now it's time to write some code
in Visual Basic 6.
In this chapter:
[B Differences between VBA and VB6
[B VB6 Project Basics
[B Controlling MicroStation with VB6
[B Compiling and Distributing Applications
807
808 I Chapter 38: Writing VB6 Applications I
files) and a single Project file (.vbp) which brings them all
together.
[B MicroStation VBA projects must be run from within
MicroStation's VBA environment. Excel's VBA projects must be
run from within the Excel VBA environment. VB6 projects are
compiled into executable programs (.exe) and can be run
independent of any other application. VB6 projects can also be
compiled into DLL files and ActiveX Controls (.ocx files) .
[B Since VBA Projects are self-contained, ch anges made to Code
Modules, Classes, and User Forms in a VBA project remain in
the project. Multiple VB6 projects can utilize the same Code
Module, Class Module, or User Form file. So changes made to
VB6 resources may be reflected in multiple VB6 projects. This
is a powerful feature but be careful that changes made to a
resource file (.bas, .ds, .frm) in one project do not negatively
impact any other project.
[B A VBA project can be distributed by providing a single .mvba
file. VB6 projects compile to a single file (.exe, .dll, .ocx) but are
best distributed using a Setup program that installs DLLs and
other resources (such as the Visual Basic Runtime Libraries)
that may be needed for the program to run correctly.
[B Since VBA programs must be run from within the host
application, we know the host application is on the user's
computer. Since VB6 compiled programs can run independent
of any host application, it is possible that someone could install
a program designed for MicroStation on a computer without
MicroStation installed.
[B Even after VBA programs are distributed, it is easy to debug
them because debugging can take place and source code can be
stepped through on the user's machine (as long as the code is
not 'Locked'). After a VB6 program is compiled, the code
cannot be stepped through or viewed on the user's machine.
[B The VBA environment is installed with applications such as
MicroStation and Microsoft Excel. V B6 must be purchased and
then installed to use it.
IVB6 Project Structure I 809
'0,'.
~. ~ ~
VB Wizard ActiveX Activex Addin Data Project
~tanager Document DII Document Exe
open~
Cancel I
Help
EJle !;.dit I£iew !:roject FQ!'mat Qebug Run Q>tery Diagram Iools 8.dd-Ins 't£indow t!elp
The IDE of VB6 is nearly identical to that of VBA. Here, we can see the
Proj ect, Properties, Toolbox, and User Form.
Let's take a couple of controls
from the Toolbox and place
them on the Form. We will level
The Make Project dialog box displays and here we specify a file location
and a file name.
I
Save jn: \C) VB 98
r------------c~--·---------------------_,
liD ~lSXM Addln t:! XlsXml I
it:! RainyDayCode Addin L:l C2. EXE
!IDSetup L:lCVPACK.EXE
IbsummarYlnformation LtL.i~<~~~:
ie::)Templa t e i : J . V86.EXE
it:! Wizards t:QVISDATA.EXE
~
File name: IP,oiect1 .exe
Cancel I
Help
Qptions...
are not going to use this new Form so Ij IirH;;·b·I~I ,)!, ~_~~I"
we will remove it by going to the
Project - Projectl f3
Project Window and right-clicking
on the Form, then selecting Remove E· Project! (Projectl)
J
Forml . ["I e::J Forms
. El l'1l!p-!II!!
.I!II
. ,,1m""""',",
. I!!I
.. in..
E!!il ViewOWect
After we remove the new default ,<L .. • '::'w~'" 1m View CQde
Form, we can see that we now have a ~ ~ Prope[ties
____'_·H' _____ H" •••.•.• _ •••. •
.
_
.
_
,
~
.
'
_
'
_
~
_
'
_
~
"
.
Iformi Form 2ave Forml
nothing in it. Let's add the Form from Save Forml 8.5".
Component" ,
Generall
Startup Object:
IStanchrd cXe ~ lii1&mii=iiliiM~
Project Name:
IProject! Project Help
Help File Name: Context ID:
~ fO
Project Description:
I OK Cancel I Help
Let's talk about this dialog box. We can see the Project Name is being
shown as "Projectl". Let's change this to "Project2".
The Startup Object selection is critical. At this point the setting is "Sub
Main". This means when we run this program either at design time or
runtime, it looks for a procedure named "Main" in a Code Module. For
our example here, we don't want to start with "Sub Main" because we
don't have a "Sub Main". We want to select "Forml" from the list. The
Startup Object ComboBox contains the names of all User Forms that
can be used as Startup Objects. If we had Forms named "Form2" and
"Form3" in this Project they would show up in this list as well.
814 I Chapter 38: Writing VB6 Applications I
Now that these changes have been made, the Project Properties dialog
box should look like this:
General I
Project Type:
tStaf1d~~rd EXE
Project t:/ame:
2):artup Object:
-=:J lMSH,! -,::::J
1Project2
Project Help
t!elp File Name: Context [D:
d 10
Eroject Description:
~at1cel I Help
When we click OK we can now save our Project. When we click the Save
button, we are asked to name and specify a save location for the Project
file.
i~ Projectl, vbp
1
The name of the .vbp file defaults to the Project Name set in the Project
Properties dialog box. In this case, we will accept the default name of
Project2. vbp. We are not asked for the location or name of the Form
because it had already been saved in our previous Project. The .frm file
is saved with the new controls on it and with its new size properties.
Let's remove Project2 by going to the VB menu and selecting File>
Remove Project2. Now, we will open Projectl again.
I VB6 Project Structure I 815
When we open "Proj ectl" again and look at "Form I " it reflects the
changes made when it was being used in "Project2". This 'linking' of
program design elements into projects is powerful. But as with most
things that are powerful, we should be careful so we don't abuse it either
intentionally or unintentionally. If, for example, we forget that FormI is
being used in two projects, we may make modifications to it in
"Project2" that causes it to stop working properly in "Projectl ".
Now, we compiled Projectl before we began Project2. We made changes
to FormI when we were in Project2. What happens when we execute
Projectl.exe? Do we get the new Form or do we get things as they were
when we compiled Projectl? Answer: when we compile a program,
everything is compiled into the executable as they are at the time the
project is compiled. The executable program does not change to reflect
modifications made to its design elements. If, however, we open and re-
compile Projectl, the new executable (.exe) reflects the changes that
were made up to the point that we re-compiled the project.
This exercise teaches us a few very important principles.
(E Multiple VB Projects (.vbp files) can make use of the same
resource file (Jrm, .bas, .ds, etc.) .
(E Compiled .exe files are static. Changes made to design elements
compiled into .exe files are not reflected in the .exe file unless it
is re-compiled.
(E By default, compiling an .exe file does not result in saving
source Jrm, .bas, or .ds files. It is possible to create an entire
program using VB6 and compile it without saving any of the
source files to disk. Although potentially dangerous, this can be
useful when we want to make a fairly significant change 'just to
see what happens' and we don't want to lose our 'working' code.
We can make changes, run it in design mode or compile it, and
'see what happens'. Only after we know the code works properly
do we save our project. On the other hand, if we want VB6 to
automatically save our project each time we compile our
project, we can change a Tools> Options> Environment Tab>
When a program starts setting.
Thus far we have created two "Standard EXE" projects. There are two
other note-worthy projects and they are:
816 I Chapter 38: Writin g VB6 Applications I
[B ActiveX DLL - Allows us to create a 'program' that can NOT
be executed by itself but other programs can 'connect' to it. An
example of an ActiveX DLL would be the "Microsoft ActiveX
Data Objects Library". We cannot 'execute' it so it runs as an
independent program but we can 'connect' to it to allow easy
access of databases.
[B ActiveX Control- Allows us to create our own 'Controls' that
show up in the Toolbox in VBA and VB6. An example of an
ActiveX Control is a ComboBox that automatically displays the
list of Levels in a .dgn file. We would begin with the basic
ComboBox and would write code to populate it. Once
completed and compiled (to an .ocx file) we would be able to
drop it onto a Form in MicroStation's VBA environment and it
would automatically populate with Levels.
Available References: OK
Cancel
Browse ...
Priority
Help
Li
r- Bentley MicroStation DGN 8. 9 Object Library .•- •.......--..- ..- ..- ----..--.--•.-- ... -... ..-.......•
I
!
1
Execute J
Let's review the code now. We know we want to connect to
MicroStation. We do this by using GetObj ect and use the
MicroStationDGN.ApplicationObjectConnector as the Class we
'Get: Then we get the Application Object from the
ApplicationObjectConnector. Once we have the Application of the
ApplicationObjectConnector, we are able to work with MicroStation in
the same way we do in VBA.
We place the name of each Level in the ActiveDesignFile into "Combo!".
If a CellLibrary is attached, we add the name of each Cell in the Library
to "Comb02".
And what happens when the user clicks the Button?
filel.d
filel 0.dgn
file2.dgn
file3.dgn
6:l Active>< Control Pad file4.dgn
L.:J BatchProcessing fil e5dgn
I2J cd material file6.dgn
file7.dgn
CJ docs file8.dgn
EJ Documents file9.dgn
EJ Fonts filea.dgn
CJ from mark fileb.dgn
ILl pies rasterdocs.dgn
EJ Source Code
EJ USG S
EJ VB6
I
,
Levell
Level 2
Level 3
Level 4
I Level 5
Level6
Level 7
I Level 8
~
.LeveI9
Level 10
jLeVelll
Level 12
.--~
I Controlling MicroStation with VB61 821
....
~ ~ h 17 fj:'
Standard EXE ActiveX EXE ActiveX DLL
[II VB Application
Wizard
'3\"
~. ~ ~ ~ ~
VB Wizard ActiveX Activex Addin Data Project
~lanager Document DII Document Exe
v.
""~ ""~ "" ~
Open ~
Cancel 1
Help
"msvba_modeltree". Alphabetic I
Categorized I
~~!?~.~~~deltree
~s.~.e.~~.~.~.Y.~
3 Right-click on the Toolbox, Ali9nable .: F~I;~
!
L Location: C:\WINDOWS\system32\filemISO.ocx
--.---.. -.-----.--.-----.------------------.--~
i
OK Cancel
824 I Chapter 38: Writing VB6 Applications I
4 Add a TreeView control to the UserControl area and name it "tvl".
5 Change the "Style" property of the Tree View to "7 -
tvwTreelinesPlusMinusPictureText".
6 Add a Reference to "Bentley MicroStation DGN 8.9 Object Library"
in the Control Project (Project> References).
We now have the framewo rk for our n ew Control.
Function GetModelO As
MicroStationDGN.ModelReference
Similar to GetLevel, GetModel returns a Model Object if one is selected
in the Tree View.
1m Ei I ~ . J
1';1" itl msvbaControls (msvba_mode ltree.vbp)
. to}·a User Controls
. : ~ msvba:"'modeltree (msvb,Cmoqeltree .ctl)
;:':] ~ Project! (testingmodeltree.vbp)
EJ.·a Forms
L.. t:J.
Form! (testingmodeltree .frm)
When we look at the Project window now in VB6 we will see that we
have two projects loaded. When we are working in a Project Group, one
of the projects is set as the "Start Up Project". Controls cannot be
'executed' by themselves so we will set our new 'testingmodeltree'
project as the Start Up Project. We do this by right-clicking on the
Project and selecting "Set as Start Up".
Now, in the Project window,
double-click on the Control we
just created so that it displays.
N ext, we are going to close the
Control by clicking the Close
button at the top of the window.
. '.
! Controll ing MicroStation with VB6! 829
When we run our new Project, the Form is displayed and the Tree View
is available.
B Models
. Building and E"isting Mesh
Buildlng Site Elesign Mesli
, Cut and Fill Volume
Existing Terrain Mesh
Finished Br,ilding Site
Index
EO Levels
Building Site Terrain
BuildingSiteMesh
Default Y;
At this point, we have created a new ActiveX Control and have added a
new Project that makes use of the Control. Let's add a little bit of code
now to the new Project so we can test the Event and Methods of the
Control. We also need to add a Reference to the "Bentley MicroStation
DGN Object Library".
830 I Chapter 38: Writing VB6 Applications I
Priva te Sub msvba_m odel treel_SelectionChanged( _
SelectedN ode As MSComctlL ib .N ode)
Dim myLevel As MicroStatio~DGN.Level
Dim myModel As MicroStationDGN.ModelReference
MsgBox SelectedNode.Text & vbCr & SelectedNode.FullPath
Set myLevel = msvba_modeltreel.GetLevel
If myLevel Is Nothing = False Then
MsgBox myLevel.Name & vbTab & myLevel.Number, , "LEVEL "
End If
Set myModel = msvba_modeltreel.GetModel
If myModel Is Nothing = False Then
MsgB ox myModel.Name & vbTab & myModel.Description, . " MODEL "
En d If
End Sub
Here is the "SelectionChanged" event we created in our Control. We
display the selected node's Text property and its FullPath property. Then
we use the GetLevel and GetModel methods.
Now, type:
! Contro lli ng MicroStation wi th VB6 ! 831
regsv r 32 . exe "C: \ Mi cro Sta t i on VBA\ msvba _m ode l tree . ocx "
and press the <Enter> key. The path entered needs to point to the
location of the .ocx file. This .ocx file may be in a different folder so the
path may need to be adjusted.
When we press <Enter>, if everything was entered correctly, we will see
the following dialog box:
li::.:::::i:*:::::ij
Available Controls:
o MSCustomLog Control
o MSDTHostCtri Class ~
o MSDTHostCtrl Class
o MSDVDAdm Class
~
o MSFlexGridWizard.Sub\llizard
o Msie Control
o MSNCSALog Control
o MsnMusicStatusUi Class
o MSODBCLog Control
o MSRE dit Class
I8J msvbaConl161s 'msvba":rnodeltre.e ~~ Show
o M5\11 ebDVD Class o Selected Items Only
msvbaControls.msvba_modeltree
Location C:\MicroStation VBA\msvba_modeltree.ocx
Our new Control should show up in the list. When selected, it displays
in the Toolbox inside VBA.
Drag and drop the Control on to the Form and size it. Then press the
<FS> button to Run the form.
832 I Chapter 38: Writin g VB6 Applications I
A MessageBox may display warning us of the use of this ActiveX
Control. After getting past this dialog box, the Form is displayed and the
Control is populated with the Models and Levels in the Active Model
Reference.
Creating ActiveX Controls is fairly simple and straight forward. We have
created one that interacts with MicroStation. So, the next time we see a
User Interface in MicroStation or another application we wish we could
use, we can create our own control complete with its own Properties,
Methods, and Events. These custom controls can be used from within
VB6 and in VBA.
Open ~
Cancel " I'
Help
1msvba_WinAPI
Project Help
tielp File Name: Context 10:
10
E.roject Description:
:;7i:'!!t" '"- c ,~ .::{ ,,;;:)~~ >:"~W"~('· • ""J' ~ < .. ,~~~--:r:ry_f ~~~,,,,- :'..7 ..... ...,.::;..~ _.
~"
r ~o Compatibility
r. !:roject Compatibility
r !linary Compatibility
Const SM CXSCREEN 0
Const SM CYSC REE N
Available References:
OK '. 1
I~: Visual Basic For Applications
I~ Visual Basic runtime objects and procedures
. Cancel " I
i0 Visual Basic objects and procedures
i0 OLE Automation Browse .. , 1
l~i I. I·
Compiling Applications
~ew Project Ctrl+N
When it is time to compile an
~ Qpen Project". Ctrl+O Application in VB6, select File> Make ...
Agd Project".
Remove Project The text we see after the word "Make"
IiiI Saye Project Group differs based on the name of the project
Sav!l. Project Group As ... and what type of project we are working
2ave frmTestSystemDLL.frm ctrl+S in. In addition to seeing "Make" and a
Save frm TestSystemDLL.frm as ...
project name we may also see "Make
5a'./8 CD.anqe Script Project Group". Make Project Group is
~ erint. .. ctrl+P used to compile all Applications in the
III Print Set~". current Group .
• ,MiMM#WWU4i\f*"
~lake Project !aroup... ., So, compiling an application is very
! TestSystemDLL..vbg simple. We can see the menu items here.
~ msvba_WinAPI. vbp
~ msvba_modeltree.vbg
But when should we compile?
:1 Projectstructured. vbp
-----------c-. is possible to create an entire
It
E2(it Alt+Q
application without compiling until the
time comes that we are ready to distribute
it. In the case of an ActiveX Control and an ActiveX DLL, we can Add a
Project to the Project Group and test the Control or DLL without
compiling. If, however, we want to test a Control or DLL in another
application such as MicroStation's VBA environment, we need to
compile it. When it comes to Standard EXE projects, compiling a project
may be useful during the development process to test performance.
When we run a program in Design Mode (when we can break into the
application, step through code, etc.), VB6 applications run much slower
in design mode than when they are compiled. By default, compiling a
VB6 application causes a more thorough check of our code by the
compiler. Errors in Modules, Forms, Procedures, Functions, etc., that
were not identified when we ran the program in Design Mode will
surface when we compile a project.
Compiling a VB6 project usually results in an .exe file (Standard EXE),
an .ocx (ActiveX Control) or a .dll (ActiveX DLL) file. It would appear
as though we could e-mail or distribute this one file to anyone in the
world and our program would work on their computer just as it does on
ours. And this may work from time to time but this is not always the
case.
I Compiling and Distributing Applications I 839
I Location: C:\WINDOWS\system32V~QOA.DLL :
~
L • • _w _ _ _ _
Language:
_____ _
Standard
_ __ _ _ , . __• _ _ _ • _ _ _ • _ _ ••• _ _ _ • • • _ _ _ •• _ _ _ •• _ . _ _ . _ . _ _ •••••••••• _ . _ _ _ _ •••••••••••• _ . _ _ •••• __ ••• _ •
i
.l
840 I Chapter 38: Writing VB6 Applications I
H ere we can see a large number of References. The top four shown are
standard to any VB6 program. We don't need to worry about them. The
other References that are selected are the ones that should concern us.
When an item in the References list is selected, its full path is shown
after the "Location" label.
The other area we sh ould look into is the Toolbox. If, for example, we are
using a Tree View control, we need to make sure that th e file containing
the Tree View control is distributed.
!l.rowse ...
[
~liCrosoft Windows Common Controls 6.0 (SP6) - - - - - - - -- -------:
Location: C:\WINDOWS\system32\MSCOMCTL. OCX !
••••••••••• _; ...... _ ..... .. ....... . .. .................. . ........ _ . , ••••••' •• •• • :, ... ....... . ......... . ... _ •••• •• • • • _ ••.•• •••• • _ •••••• •••••••• _ ••••• ; _ • •••• • _ •••• ••• • • ................. . . h . . ....... _ ••• _ . .. . .. .. . ......... ................... _i
. 0K . I Cancel I ,t'.Pp!,'
OK. We know which files we need from the References and the Controls
area. We know that we need to Register DLLs and ActiveX Controls on
the host computer. How do we best do this?
We have already used the RegSvr32.exe registration process. We could
place a series of these registration commands in a batch file (.bat file).
We could then compress these source files and registration batch file
into a zip file. Although this solution would certainly work, it is far from
elegant and user friendly.
Let's examine the solution that is shipped with VB6: the Microsoft
Package and Deployment Wizard. It is found in the "Microsoft Visual
Basic 6.0" Start menu.
~
Bundle this project into a distributable package, such as an
Internet cab or a setup program.
~
Send one of this project's packages to a distribution site, such as
an Internet server.
~eploy
Manage
Scripts
Close Help
842 I Chapter 38: Writing VB6 Applications I
2 The next dialog presents the choice between a "Standard Setup
Package" and a "Dependency File': We will select a Standard Setup
Package.
f'.ackage type:
r",rll\UI"i!lfll!ll!ft@l" .
D;ndency File
Q.escription:
Use to create a package that will be installed by a
setup. exe program.
Help Cancel : I
f'.ackage folder:
IC:\Program Files\~licrosoft Visual Studio\VB98\Package
~C :\ ell j9c: :3
Ell Program Files ,. =11
aMicrosoft Visual Studio :. ...1
Network...
Q] MSXM Addln
G;:3 RainyDayCode Addin Ne~Folder ...
This step is also important because we can Add files to our Setup
package that may not be added automatically. For example, if we
have written a User Manual and created a PDF file of it, we can Add
the file in this step and it will be compressed with the other proj ect
files and 'installed' on the user's computer.
• " <.~ ~ ., -~' IT , •• t"', , ' ' : """,-~ .~"'., ~ ~ j'" • "~r""." ~ ""'r> «~J:"If'I'}'.)t":' i'""'~"'iii:1!:'·>1<'f'~_~T'
FUes:
Name Source "" B.dd" .
0 SETUP 1.EXE c:\Progr am Files\Microsoft Vis
o SHELLLNK.TLB C:\WINDOWS\system32
o ST6UNST.EXE C:\Program Files\~licr osoft Vis
o V86 Runtime and OLE Automation
o V86STKIT.DLL C:\WINDOWS\system32
5 After verifying which files are to be included in the Setup file, we are
asked whether we will be distributing the setup as a single file or if it
is to be placed on multiple floppy disks (outdated but still an
option) .
You can create one large cab file or multiple cab files for your
package. If you are going to distribute your application on
floppy disks, you must create multiple cabs and specify a cab
size no larger than the disks you plan to use , Choose the
appropriate option below.
r Cab options
i r. :2ingle cab
Installation title:
!MicroStation VBA Sample
Cancel ~ !l.ack
8 The files that have been included in the setup package must be
placed somewhere. By default, DLLs and OCX files are placed in the
I Compil ing and Distributing Applications I 845
You can modify the install location for each of the files listed
below by changing the macro assigned to the file in the table. If
desired, you can add subfolder information to the end of a
macro, as in $(ProgramFiles)\CVlySubFolder.
Flies:
Name Source Install Location
MSCOfV1CTL .OCX ' ~ :\VVIN~()VVS\systeIl13~ .... $(WinSysPath)
.... ... .. .. ..
, .
Shared files :
Name Source
o Projectl.exe C:\Program FilesV1icrosoft Visual Studio\VB91
< I.
Help Cancel
846 I Chapter 38: Writing VB6 Applications I
10 The last dialog box we have to deal with allows us to specify a Script
name.
~.-~~';"'"'"',.....~~ ~:""~~~,,,!,~ ~~~........ ~~ ~
;i.:J~~!!C~e and Dep[oyrnent,~iz~rd: ~ ~~~i§h,e~l " '" ,."",~",.,," "",:, ,; . ~'f.', ' ~
The wizard has finished collecting information needed to build
this package, Enter the name under which to save the settings
for this session, then click Finish to create the package,
After we click the Finish .. ;;;;p.f ........h~~. .""~;;-< ;;,v~':Jt K .~"'. "f'r~' ""-~"':;'''';. ,"""11-';",""""',,\ ~ '<~~"">' 1'''\/,t."-",,,,!'7~'''''''''·'
The cab file for your application has been built as 'C:\Program
Files\~licrosoft Visual Studio\VB9B\Package\Project1.CA8',
REVIEW
VB6 has an environment that looks and feels a lot like VBA. In addition
to creating stand-alone programs, we can create our own custom
ActiveX Controls as well as ActiveX DLLs. When we finish our
programming and compiling, we can distribute our application by using
the Microsoft Package and Deployment Wizard which ships with VB6.
Once we 'attach' to MicroStation, developing in VB6 is nearly identical
to developing inside of MicroStation's VBA environment. All of the code
we have created and worked with inside of MicroStation VBA can be
'ported' to VB6 with very little difficulty.
848 I Chapter 38: Wri tin g VB6 Applications I
There is one thing we need to be careful about when 'porting' a VBA
program to VB6. When we are working in VBA, several Objects are
naturally exposed for our use, the Application object, for example. In
MicroStation's VBA environment, we can type
On the surface, it appears as though VBA, VB6, and VB. NET are
identical. They each bear, in part, the title "Visual Basic" and make use
of the same "Visual Basic" basics. And yes, they are very similar. But
there are also differences between them. VBA and VB6 have much more
in common than VB.NET. The differences between them (VBA and
VB6) and VB.NET can be quite significant, depending on which 'area'
we are considering. When Microsoft introduced the VB.NET
environment in 2003, one of the aims was to make Visual Basic much
more Object-Oriented. This is one of the primary differences between
VB.NET and VBA or VB6.
This chapter deals with not only controlling MicroStation in VB.NET
applications but also concentrates on the differences between these
environments so we can become more proficient in the VB.NET
environment and language. We will be using Visual Studio 2005 for our
discussion.
In this chapter:
[B An Introduction to the VB.NET Environment
849
850 I Chapter 39: Using VB.NET I
[B The Future of VB. NET with MicroStation
VB.NET INTRODUCTION
Let's take a look at the VB.NET environment. The first thing we should
get out into the open is the fact that whereas VB6 is an Application and
VC++ is its own Application, the .NET environment is used for
developing Applications in VB, C# (pronounced C Sharp), J#, etc.
Adding 810g9in9 to Your Apps with My.Blogs and Visual Basic •.• JoJ,;
Fri, 27 Jan 2006 05: 56:02 GMT· My,Blogs is a collection of sample code r.1,:.;'
that shows how to easily provide programmatic access to blogs in your f
applications. Chris Mayo shows how easy it is to reed and pubUsh blog ' !l
entries within Visual Basic 200S using My ,Blogs. ~ j
Visual Basic: Navigate The .NET Framewo rk And Your Projects ". f i
Tue, 24 Jan 2006. 16:58:48 GMT· One of the biggest issues that ri
Open: Project .. , IWeb Site., r~1n::ee~se~~~I~:~ ;~rt~ep~~~~~I~~~~~~hq~~t~NJ~~~i~~ ~~~c~~ke ~ ,[
Create: Project... IWeb Site, ,, Mackenzie shows how the My namespace in Visual Basic 2005 will make .!
Conver ting a Dfl ta -Ol'icnted Application from Visual Basic 6 to ... ~ 11
Tue, 24 Jan 2006 18:24:04 GMT· Ken Getz and Paul Sheriff show you tii{jjj
how to migrate your data-oriented application from Visual Basic 6,0 to f ;li
Visual Basic 2005 in Part 3 of this series. F{[
HowDoI ... ?
What's nell'} in Visual Bastc 2005?
Cha nnel 9: M]X with aill Gates in Vegas 'l!
Mon, 23 Jan 2006 23: 11:59 GMT· Watch the MIX content team in action
Create 'four First Application as they talk about their plans for this new conference happening at the
Use a Starter Kit Venetian hotel in Vegas.
le,3rn Visual Basic User Interface Contro ls in Visual 8asic 6 a nd Visual Oasic 2005
Connect With the Comrnurlity
Fri, 20 Jan 2006 20:08:28 GMT· When upgrading Visual Basic 6
Download Additional Content
applications, Uttle causes more concern than controls that just wont
convert -in-project controls, custom ActiveX controls, built-in controls,
etc. B~I Sempf shows you how to ease this process,
Press Release: lnb'oducing tlelpStudio lite tlelp Authoring Tool
Wed, 18 Jan 2006 19:08 :34 GMT· The Visual Studio 2005 SOK ships with
a free tool for authoring Help content and integrating it with Visual Studio
2005. HelpStudio lite, built by Innovasys, Ltd" Is a lightweight version of
HelpStudio, optimized for Visual StudiO Industry Partners.
Register Now for the MIX '06 Conference in Las Ve gas
Give us feedback , suggestions, or
tell us about bugs in Visual Studio Fri, 13 Jan 2006 t 7:59:25 GMT - Attend the MIX conference, a LIVE !
2005 conversation between web developers, designers and business leaders,
being held in las Vegas from March 20 - 22 at the Venetian hotel with Bill
Gates and Tim O'ReiUy ,
From the Start Page of Visual Studio 2005, we can create or open new
Projects. Tn addition to the ability to create new projects and open
existing ones, we can see the RSS fe ed from Microsoft's MSDN Visual
Basic homepage. (We discussed RSS technology in an earlier chapter.)
I VB.NET Introduction I 851
"
..vB
Starter Kits ~ ~ Jill
I±I Other Languages Windows Class library Consale Windaws Web Control
I±I Other Project Types Application Applicatian Cantrollibrary Library
~
Empty Project
--
1... ............................................_..... _....... .
I A project f or creating an application with a Windows user interface
Name: i ~licraStatian Contral A I
~[ Cancel
I. OK ~ I Cancel
2 Select the COM tab and scroll down to "Bentley MicroStation DGN
# .# Object Library". Clicking the OK button adds the Reference and
we are ready to continue.
852 I Chapter 39: Using VB.NET I
3 Double-click on our Proj ect Name in the "Solution Explorer" and
then select the References tab to display all the references of the
current project.
File Edit View Projett Build Debug Data Tools Window Community Help
~================================-=--=,--=---~--It-===--=--=======I
Ready
myMSApp = Nothing
myMSAppCon = Nothing
End Sub
End Cl ass
The code should look very familiar. It resembles the code we created
in VB6 as well as code created for Microsoft Excel. One of the main
differences between what we see here and what we used before is the
absence of the "Set" statement when we are working with Objects.
Why is this? Because all variables are Objects in VB.NET. Strings are
Objects. Integers are Objects. So, we don't need to use "Set" when we
are assigning variables their values or objects.
If we look at the MessageBox statement, we see that we are using
parenthesis in VB. NET where we do not do this in VB6 except when
we are getting a return value. Any time we use a Function or
Procedure in VB.NET that uses Parameters, we surround the
Parameters with parenthesis.
8 If we try running our code, we will find that the code seems to run
fine. But before doing anything else, we should save our project.
Selecting File> Save All displays the Save Project dialog box.
~I Cancel
. d MicroStation Control A ~
t~;
~:
.'}
$ 0 00000 H
HEIGHT
N II'
C) J
NORTH
L___[l?QJ__~~: '-
To- W
- e-bs-
ile- - - - - - - - - - - - - - - - - '
The concept for this application is fairly simple. We see a list of cells that
can be inserted into MicroStation with a thumbnail image of the Cell
accompanying the Cell name. We also see information about the
selected cell in a text box on the right. This additional 'information' is
stored in an .info file with the same file name as the preview image. If a
line beginning with the text "Website Address:" is found in the .info file,
a hyperlink 'To Website' is shown which, when clicked, opens a new web
browser window and opens the website address in the .info file. If a
website address is not in the .info file or if an .info file is not available,
I You can do this in VB.NET! I 857
the "To Website" link is not displayed. When the user double-clicks on
an item in the List View control, the 'double-clicked' cell is inserted into
MicroStation. To keep things simple, we will insert the Cell at the center
of the current view.
Rather than hard-code cell names and force the user to create thumbnail
images of a particular size, we base the contents of the entire list on the
availability of bitmap (.bmp) files in the Application's folder. The name
of each bitmap file corresponds with a cell name. Information Files
(.info) match the file name of the bitmap files and contain reference
information about the cell. A thumbnail is automatically created in
memory for 'use in the ListView based on each bitmap file. Each
dynamically created thumbnail is 64 pixels wide and 64 pixels high. The
source bitmap files can be any size but will ideally be square in shape
since the thumbnail image that is created does not compensate for
differences in aspect ratios.
Here is the code for this project. Keep in mind that we already have a
reference added to the Bentley MicroStation DGN # .# Object Library.
Pr i vate Sub l stvCel l s_Do ubl eClic k(ByVa l sender As Obje ct. _
By Val e As System . EventArgs) Hand l es
1stvCe ll s . Doub l eC l i ck
Di m myMSApp Con As _
MicroStationDG N.Appl i cationObjectC onnector
Dim my MSApp As MicroStat i onDGN . Application
Di m myCe llEl em As Mi c r oStat i onDG N.Cel lEl ement
Di m Ce llO r i gin As Mi c r oStat i on DGN . Poi nt3d
Pr ogressBar l.V is ibl e = True
Prog r essBa r l .V al ue = 10
myMSA ppCon = GetObject(. _
"Mi cr oStati on DGN. Ap pli ca tionO bj ect Con nec t or " )
ProgressBarl.Value = 20
myMSApp = myMSAppCon.Application
ProgressBarl.Value = 40
CellOrigin = myMSApp . CommandState.LastView.Center
Prog r essBarl. Valu e = 60
myCe l lE l em = myMSApp.CreateCe ll Element3( _
l stvCe ll s.SelectedItems(O) .T ext. Cel l Origin. True)
ProgressBarl.Value = 80
myMSApp.ActiveModelReference.AddElement(myCellElem)
ProgressBarl.Va l ue = 100
ProgressBarl . Visible = False
End Sub
Next
End Sub
End Class
Code is placed into five events which are triggered by either the
application starting or by user interaction. Let's discuss each of these
events and what they are accomplishing.
ProgressBarl.Visible = False
En d Sub
When we perform error checking in VB.NET, we anticipate that a line of
code may cause an error. We Try the line or lines of code after which we
Catch the error or errors that may arise. We will see a few additional
examples of this as we continue.
862 I Chapter 39: Using VB.NET I
CommandButton, a TextBox, a
.
,,0t,? A·F6·G-BldgExti
A-F8-G-BldgMisc
:0 A-G251-G-WaIlExtl
Folder Browser Dialog, a , ··0 A-ZOOO-D-Dim
L~~~~~~~~~.._~~~~~~_!~J~
,14 BSI300AE 10l-Plan.dgn
:····14 BSI300AE201 -Elevations.dgn
. .p. BSI300AE301-S ections.dgn
Here's what it looks ' :. ·14 BSI300AE501-Details.dgn
like when ....~ BSI300AE701-RCPlan.dgn
MicroStation is not '...p. BSI300AE9-Atrium.dgn
'. p. BSI300AE9-Core.dgn
running: , .~ BSI300AE9-Shell.dgn
,. ~ BSI300C-9-Site.dgn
: · 14 BS1300G1001-CoveLdgn
, .. ~ BSl300Gl9-3DMasteLdgn
: ··It B513001-9-1 nteriOL dgn
, 14 BSI300S-9-Atrium.dgn
'·· 14 BSI300S-9-Structural.dgn
. . It BS!30(!><-9-Sign.dgn
I A DGN Browser Application I 863
Me.WindowState = FormWindowState.Normal
End Sub
End Class
The ImageList Icons are located on the CD that accompanies this book.
Are there things we could do to make this program even more
powerful? Of course. We could automatically open a file when it is
double-clicked in the Tree. We could allow the user to drag and drop
866 I Chapter 39: Using VB.NET I
folders from Windows Explorer into our DGN Explorer. We could store
the most recently selected folders in a ComboBox instead of using a
TextBox to display the selected path. We could have the option of
including subfolders when a folder is selected. There are many things we
could do to this project but we are not going to do them here. We will
leave embellishments up to the reader.
Everything is an Object
When developing in VBA or VB6, we can declare a variable as a String.
In VBA and VB6, a String is a data type, not an Object. In VB.NET, a
String is an Object with its own properties and methods. For example,
IVBA to VB.NET Reference I 867
when we type the name of a variable declared as a String and press the
period key, we see:
.. to. , ~= r-=
,,-.,.."'~=.~.-.."'-.-, .... Substring
... ToChar Array
·F;;"'1.~b[DeSignl; ''1 ToLower ser
- •. -.~-.-------".- i~ ToLowerInvariant
.=_=== ·v ToStr ing v i
As we can see here, we can use the ToU ppe r method of a String Object
instead of using UCas e (see below).
myString.ToUpper · VB . NET
To Upper is a method of the String Object. And how about the String
Object's properties? Yes, there are Properties as well. In VB.NET, we use
the Length property of a String Object instead of using the Le n function
(as we do in VB6 and VBA).
Overloaded
That word brings vivid pictures to mind. In VB.NET it means that a
single procedure, method, function , etc., can have more than one
implementation, each with its own set of unique Parameters. Here's an
example using the FileInfo Object's Open method:
... 3 of 3 .... Open (mode As System.IO,File~iode, access As System, IO, FileAccess, share As System.IO,FileShare) As System,IO, FileStream
: Opens a file in the specified mode with read, write, or read/write access and the specified sharing option,
my FS . Clo s e ( )
End Sub
E-mailinginVB.NET
For an example of e-mailing using VBA, refer to previous chapters
where this was discussed. As for VB.NET, here are a couple of examples:
Sub TraverseFolders ()
Dim myDI As New IO.Directo ryI nfo( "C: \M i croStation VBA")
Dim mySubD I As IO.DirectoryInfo
For Each mySubDI In myDI.GetDirectories( "*.* ", _
IO.SearchOption.AllDirectories)
Deb u9 . Pr i nt( my Sub DI . Fu1 1 Name )
Next
End Sub
GetDi rectori es has three different implementations. The one shown
here allows us to specify a pattern to look for as well as the ability to
specify ''AllDirectories'' or "TopDirectoryOnly':
I VBA to VB.N ET Reference I 871
Sub FindFilesA ()
Dim myDI As New IO .Di rectoryIn f o( "C: \ MicroStati on VBA " )
Di m my FI As IO. Fil eInfo
For Each myF I In myDI.G etFiles( "* . DGN " .
IO.SearchOption.AllDirectories)
Debug.Print(myFI.FullName)
Next
End Sub
872 I Chapter 39: Using VB.NET I
In this example, we get all .dgn files beginning in the C: \M icroStation
VEA path and its subdirectories.
accomplish this we will use two Windows API calls as well as the built-in
Registry access objects in .NET.
First, here are the Windows API calls declared just below the "Public
Class" statement in VB.NET:
When this program is run , Bitmap files are created for each unique file
extension found in the specified folder.
I Distributing VB.NET Applications I 877
Publish Wizard '« ", " ' , " -' , ' , :" " ~~
How will users install the application?
Ready to Publish!
The wizard will now publish the application based on your choices .
When this application is installed on the client machine, a shortcut will be added to the Start Menu, and the
application can be uninstalled via Add/Remove Programs.
-----_._----_. - - - -.- . - - - - - - -
3 Clicking Finish causes the Publish Wizard to create the setup file.
lt takes a few moments to create the Setup file. "Publish building" is
shown in the status bar of the VB.NET IDE with an animated icon.
REVIEW
The specific API calls used to control MicroStation using VB.NET are
not different in any way when compared with Microsoft Excel or VB6.
We still add a Reference to the "Bentley MicroStation DGN #.# Library".
We still use GetObj ect. The are other differences between VB.NET and
VB6/VBA. These differences often result in greatly simplifying file and
folder access as well as other areas of programming that had previously
been difficult and tedious. There is little question that VB.NET is the
future of VB programming. Although we can continue to develop
powerful applications in MicroStation's VBA environment, it is a good
idea to become familiar with the .NET world.
Additional Sources
SQL STATEMENTS
http://msdn.microsoft.com/library/en-us/tsqlreflts sa-
ses 9sfo.asp?frame=true
SQL Statement Explanations and Examples from Microsoft
881
882 I Additional Sources I
VB.NET
http://msdn.microsoft.com/vbasicl
Visual Basic 2005 Programmer's Reference (Programmer to
Programmer); ISBN: 0764571982
MATHCAD
www.mathcad.com
XML
XML in a Nutshell, Third Edition, ISBN: 0596007647
XML Programming Bible, ISBN: 0764538292
Index
883
884 I Index I
Alias, the, 650 Atn (ArcTangent) function, 110
alignment, 362 AttachmentLog.txt, 523
buttons, 367-368 AttachmentModified event, 525
creating, 735 attachments, 519-526
horizontal, 365-368 detaching of, 524
vertical, 368-370 displaying, 381-382, 386
AlignSelected method, 366-368 e-mail, 620-621, 680-681
alphabetizing, 87 list of object properties and methods
ampersand (&),100 for, 521-522
API Calls, 649-651 list of properties and methods in, 222-
API Types, 650-651 227
apostrophe C), 6 Auto List Members, 190
Append procedure, 131, 483 autocomplete, 154
Application, MicroStation, 73 Auto-Load, 11,494,647
Application Object, 42-44,188-189, Auto-Run, 494-495
191, 193,784
list of properties and methods in, 194- B
222 backslash symbol (\), 106, 190-191
in Mathcad, 769-770 .bas (Module) files, 16
ApplicationObjectConnector, 222 BaseElement, 573-574
applications BasePoint click, 363- 364
building in VB.NET, 854-855 batch processing, 599-621
communicating with other, 784 Beep function, 128,650
compiling in VB6, 838 Before Detach event, 524, 526
compiling Microsoft Visual Studio BeforeActivate event, 527-529
2005,854 BeforeAttach event, 525
compiling VB6, 837-838 BeginUndoRedo Event, 537-538
distributing VB6, 839 "Bentley MicroStation DON #.#
distributing VBA, 501-503 Object Library, 788, 795, 817,
distributing VB.NET, 877 851
ArcElement, 75-76 Bentley website help files, 41-42, 44
arcs, creating, 301 binding, 690-691, 785-787
ArcTangent, 110 Bitmap files, 859, 873-876
arrays, 60, 77 Bookmarks, 18
changing the size of, 416 Boolean data type, 72
dynamic, 371-372, 447 Boolean value, 113-114
returning, in a function code, 60 BorderStyle property, of Image
storing file extensions to, 446 Control, 167
ASC function, 96-98 Break,20
ASCII Text files, 19, 96 Break point, 357, 465
accessing, in VB.NET, 868 Browse button, 384
batch processing in, 599-603 bubble sorting, 372-373, 377
exporting tags using, 580-584 bubble sorting function, 88-90
reading, using File System Object, 676- "B uilding" project, 571, 854-855
677
reading and writing to, 130-131
tab-delimited, 481-483
asterisk symbol (*), 105-106
use in SQL, 736
I Index I 885
buttons cells
alignment, 366- 368 adding to library, 306-307
Browse, 384 changing column designation in Excel,
Cancel, 17 1, 443 695
Change Current Selection, 357-358 changing fo rm ula in, 701
Close, 358-359 changing values in, 701
Command,164 creating, 304-307
creating, 798-802 declarations, 305
Draw In MicroStation, 737-738 finding specific Excel, 694-695
Pick, 172, 173 selecting, 346-347
Run Macro, 4 Cells Collection, 694- 695
seed file selection, 442 CGPlace Line Constrained
Select, 356-3 57 command, 349
Spin, 167 Change Current Selection Button,
Step Into, 12 357- 358
Toggle, 163 Change event, 166, 183
unassigned cursor, 337 ChangelnX property, 465
ByRef (By Reference), 64, 68 Changeln Y property, 465
ByVal (By Value), 64, 65, 68 ChangeinZ property, 465
ChangeTag procedure, 578-580
C ChangeTrackEvents Interface, 549-
.CAB files, 847 550
Cad Input Queue, 334-340, 364 ChangeType parameters, 531-532
CadlnputMessage, 334 channel levels of RSS files, 741
list of properties and methods in, 227- characters, counting, 90-91
228 CheckBoxes, 162
calendar, 669 CheckLevel function, 740
Call Stack window, 18, 27 choosing an application, 793-794
calling, 57-58 Chr function, 96
class modules, 394-395 Clnt function, 111-114
PointString element, 417 Circle element, 738-739
variables, 421 circles, 75, 297- 300
Cancel button, 171, 443 drawing, 410- 41 2
"CantBeUndone" parameter, 540 selecting center point procedure for,
capitalization, 80 298-299
of text elements, 400-402 selecting two points procedure fo r,
capturing events, 287, 493 299-300
of external applications, 793 test procedure code for, 298-299
carat symbol (A), 106 class files, 16
Carriage Return constant, 100 Class Module windows, 19, 30
case sensitivity, 80 class modules, 54, 394, 445
cataloging files, 679 adding, 52-54
Catch function, 861 calling up, 394-395
CDbl function, 111-1 13 clsTimeTrack, 491 - 493
CDO (Collaborative Data Objects), interfaces and, 392
620,680 lifecycle, 395- 396
cell addresses, 697-698 MDL Applications and, 387-388
886 I Index I
Class_Initialize event, 493 commands, 22, 348
Class_Terminate event, 493 captu ring, 352
ClassComplete property, 424-425 input initiated as, 337
classes, 52, 67, 784. see also objects CommandState.CommandN arne
adding, 524 property, 541, 548
default file name of, 394 comments, 6, 47
implementing, 52-53 compatibility, setting, 834
terminating declared, 396 compiling
Cleanup event, 399 ActiveX Controls, 830-832
Clear, 17, 161, 732 applications in VB6, 838
click events, 29 applications in VB.NET, 854
CommandButton, 836-837 Complete Word, 18
CLng function, 111-114 complexity, degrees of, 368
Close and return to MicroStation Compressed (zipped) Folders, 507
function, 17 Computer name function, 613-615
Close Button, 358-359 Configuration Manager, 854-855
CloseMode parameter, 360-361 Connection Object, 715, 719-722
.cls files, 16 Connection Strings, 563, 716, 722-
clslmagelnsertion,389-390 723
clsLineElem, 474-477 constants, 78, 100
clsModelEvents code, 527-529 ADO, 746-749
clsStandCheckA code, 626-627 cursor type, 725
adding to Standards Checker, 627-628 List, 17
clsTimeTrack,491-493 lock type, 725-726
cmdCancel_Click, 171 message boxes, 118-120
code, 18,52-54,516 QueryClose,360-361
controlling execution of, 26, l35 vbProperCase, 85
repeating, l37-l38 contents tab, 35
use of, within VBA Project Manager, 4, control events, 154- 155
6 control names, 377
viewing, 29- 30 control placement, 363
Code Modules, 30,45,51,516 control properties, 377
collection methods, 316-324 controls, 20,29, 151,353-355
Collections, 470-477 ActiveX, 669-670
colon symbol (:), 291 adding, 168
color creating, 822-826
changing active, 333 initializing, 829
changing line, 293-295 properties for ComboBoxes, 160-161
Color Table, 294, 318-319 properties for ListBox, 161
ColumnCount property, 160 properties for TextBox, 159
ColumnCount property, for ListBox registering, 830-831
control, 161 standard, 27
columns, 555,695 in Toolbox, 152,668
COM interfaces, 784 TreeView,822-826
ComboBoxes, 29, 32,160-161,817- use offrame with, 164
818 ControlTipText property, 158, 360
command area, 330 converting
Command Buttons, 164 strings to numbers, I II
CommandButton,29 supplied parameters to doubles, 11 2
I Index I 887
MicrosoftSpeechObjectLibrary, 679 N
MicrQStation, 18 Name property, 189
MicroStation named group search, 323
attaching to project in Visual Studio naming
2005,852-853 controls, 155
controlling with VB6, 81 6 conventions, 79, 156,355
creating new instances of, 790-791 variables, 78-79
Excel versus, 793-795 .NET Framework, 872
MicroStation DGN file, 74 New (keyword), 789-790
MicroStation VBA Help file, 39 New method, 692
MicroStationDGN .ApplicationObj ec "NotifyIcon" Control, 863
tConnector, 818- 819 Now function , 122, 287, 660
MicroStation-Specific variable numeric functions, 103
types, 73 NumericValue, 760
Mid function, 91 - 92 NumericValueObject, 760-761
Midpoint property, 463-466
minimum and maximum points of o
selected text, 369-370 Object, view menu, 18
minus symbol, 104 Object Browser, 18,24,42-44, 149,
MkDir function, 124-125 757
Mod function , 114 description of, 188- 190
ModelChange event, 527-530
modeless dialog boxes, 353 displaying Members of the Object,
mode1ess form display, 173, 361 671-672
ModelReference Object, 74 opening Microsoft VBA Help in, 40
list of properties and methods in, 238- object data type, 72-73
241 Object Model, 42, 784, 786
module files, 16 Object Names, 784
modules , 45-46, 67 objects, 29, 469
insert, 19 accessing, in a collection, 471-473
opening, 30 application type of, 506
MonthN arne function, 86 creating, 462 - 469
MouseDown event, 155 DataBaseLink, 552
MouseMove event, 359 removing, from a collection, 474
MoveFirst method, 727 returning, 63
MS_STANDARDSCHECKERAPP setting, 76- 77
S,647 in VB.NET, 866- 867
MS_VBA_OPEN_IN_MEMORY, OLE Documents, 681- 682
495-497 OLEDB connection, 554
MSCatalog table, 552, 561 , 565 OnDesignFileClosed event, 286,
MsdDesignFile Format, 243 493, 507, 509-510
MsLink property, 552, 565, 588- 589 OnDesignFileOpened event, 286,
multi-criteria collection method, 493,506
32 1- 324 OnProjectLoad procedure, 495 , 647
Multipage control, 165 OpenAlertDialog Box, 432
multiple users, log files for, 61 3-615 OpenDesignFileforProgram, 386-
multiplication, 105- 106 387
.mvba extension, 3, 61 3-614 OpenDesignFileOpened, 506
myExcel, 690-691 OpenDialog method, 446
896 I Index I
opening files, 386, 438 Point3d type, 279, 283, 463
OpenSchema method, 746, 751 PointElems array, 292
operating system, determining, 653- points
655 capturing, 337
OptionButtons, 162-163 user selection of, 363-364, 414-416
option explicit, 67, 80-81 PointsByLine function, 341-344
Options, 20 PointsByRectangle function, 345-
Order By statement (SQL), 732-733 346
Order of Operations, 116 PointString, 416, 417
Outdent, 17 PolarPoint function, 62-63
Output, 483 polygons, creating, 296, 412-414
overloaded methods, 867-868 PolyTest, 412-414
PopulateFileList, 384-385
p populating
Pages.Add method, 165 a collection with levels, 474
Pages.Count method, 165 ComboBoxes, 817-818
Pan operations, 183 porting, 847- 848
ParamArray, 57-58 Preserve (keyword), 416
Parameter Info, 17 Print, 17
parameters, 47-49,57,65,68 Private (keyword), 66
"parcel" table, 553 Private Sub FormLLoad, 859
Private Sub FormLResize, 860
parenthesis, using, 853 Private Sub LinklabeLLinkClicked,
in VB.NET, 868 860
passwords Private Sub IstvCells_DoubleClick,
protecting, 498-500 860
requesting from user, 661-662 Private Sub
Paste, 17 IstvCells_ItemSelectionChange
Path property, 189 d,859-860
paths, 451-452,656-657 problem report, 645- 647
Pause Recording Macro, 11 Procedure, 19
PCE_CircTest, 410--412 procedures,6,55,57-58,66
PCE_LineTest, 407-408, 417-420, processing, 606-608
424-426 processor time, maximizing, 426-
PCE_PointStringTest, 414-416 429
PCE_PolyTest, 412-414 project, creating a VBA, 46-47
PCE_RecTest, 409 Project Explorer, 18
PCE_TestLine, 420--424 Project Explorer, 23
personalizing help fi les, 38 Project Groups in VB6, 827-828,
pFileExts, 447-450 837-838
Pi function, 59 project manager, 3
Pick button, 172, 173, 363 projects
PictureBox control, 873 creating in Microsoft Visual Studio,
pipe symbol (I), 729 851
Place Block, 341-343, 350 distributing, 500
Place Line command, 341-343 protecting, 498-499, 811
PlaySound function, 662-663 un-signed,502-503
plus symbol (+), 104 prompt area, 330
Point List Reader, 174-177
I Index I 897
storing testing
confidential information, 449 ActiveX DLL, 836
information, 615-616 clsTimeTrack, 493
point selections, 366 default path, 451-452
settings, 387, 632 DrawLinePerp method, 467
StrComp function, 87-88 file extensions, 447-450
StrConv function, 85 startpoint and endpoint, 464
string data type, 72, 83 TestMatchProperties, 361
string type variables, 32-33, 70 text alignment, 362
strings text boxes, 37-38,364
buffered, 652, 653 text elements
concatenate strings, 100 capitalizing, 397-398, 400-401
counting character, 90-91 comparing, 87
in VB.NET, 866-867 creating, 303
StringValue in Mathcad, 761 determining number of, 369-370
"Structured Storage" Documents, text files , 95-96
681-682 TextBox control, 158-159
Style property, 169 TextElement Object, 76
SUB (keyword), 55 "TheAttachment" parameter, 521
subfolders, 870-871 Thumb,166
subtraction, 105 time, tracking, 490-493
Summary Properties, 682-684 Timer function, 124
Title parameter, 120
T Toggle button, 163
Tab Order, 18 ToMiles function, 107-108
Tab strips, 164 Tool Tip, 32
tab width, 20 Toolbars, 18
tab-delimited files, 483 toolbars, 22-23, 798
Tablndex property, 157 Toolbox, 18, 840
tablename field, 552 controls in, 27, 152,668
tables, creating, 555-563 Tools Menu, 20
TabStop property, 157 Top property, 156
Tag property, 158 ToUpper method, 867
tags, 571-578 tracking, 615
extracting information, 707- 711 transaction logs, 619-620
TagSetName, 573 translating standards, 485-487
Tagsets, 575-576 traversing a folder and subfolder,
TakeFocusOn Click property, 164 870-871
Tan (tangent) function, 107-110 Trim function, 86
temporary message, 331 Try function, 861
temporary storage location, 513 .txt files, 445
terminology, 32 Type Libraries, 20, 785
"Test Connection" message box, types, 279-283
560-561 API, 650-651
TestCadlnputN, 352 available in MicroStation VBA, 281 -
282
MicroStation-specific variable, 73
returning, 62-63
standard VBA variable, 70-73
900 I Index I
U variables, 6, 66, 68
UCase function , 84 adding a watch to, 192
UDL files, 557-560, 563,715-719 calling, 421, 469
connecting to Excel file, 750-751 configuration, 496-497
opening a connection using, 722-723 defined,70
RSS and, 741 as dynamic arrays, 371-372
UnassignedCB input, 337 MicroStation -Specific, 73
underscore character C), 60 naming conventions for, 78-79
Undo, 17 as new class type, 395
Unload Me, 171 as private, 66
un-signed projects, 502-503 as Public, 450
unsupported levels procedures, setting, to an object, 786
finding, 480-482 as a string, 435
Update method, 729-730 types of, 70
Upper case function, 84 using, 81
user feedback, 375-376 variants, 61, 67, 73
providing, 379-380 VB6
User forms, 49,860 differences between VBA and, 807 -808
exporting to a new design file, 377 -379 MicroStation, 816
VB6,812 structure of projects, 809
user input, getting, 334-337 VB6 Virtual Machine file, 839
user interface exercises, 167- 174 VBA
user interfaces, 566-567, 608-613 differences between VB6 and, 807-808
U serForm, 19 overview, 1-5
code, 286 string functions in, 84
Initialize event, 168-169,360 variable types in, 70-73
toolbar,23 windows, 23
users, capturing current, 287 VBA editor, 12
VBA Files From Levels form , 380-
V 381
Val function, 113 VBA IDE, 15-30
validating path, default, 451-452 VBA Project Manager, 3-5, 7, 9-13
Value property, 162, 163, 165, 166, elements of, 10
167 VBAPM,3-5
values, 63 vbCr constant, 100
assigning, 76-77 VB.NET,850
constant, 78 vbProperCase, 85
retrieving cell, in Excel, 694-695 vbTab constant, 101
retrieving in Mathcad, 773 vertical order, 369-371
returning function, 872 View Code, 29-30
tag, 572 View menu, 18
visible property, 157, 164
Visual SQL Query Builder, 557, 562
Visual Studio 2005, 850
voice capabilities, 679
I Index I 901
W
Watch Window, 18
watch window, 25, 130
watches, adding, 192
WeekDayName function, 85-86
WeekDayNumber function, 85-86
Where statement (SQL), 732
While ... Wend statement, 137-138
Width property, 157
window menu, 21
Windows API Calls, 872
Windows API functions, 45, 382-
384,649-650
Windows Registry, 615-616, 632-
633,872
Windows Status Notification Area,
863
WithEvents (keyword), 286, 506,
792-793
WithE vents form, 469
WordWrap property, 159
workbooks, 692-693
worksheets, 692-694, 701- 702
wrappers, 832
Write Out File, 177-178
Write-Only property, 449
writing files
ASCII, 130-132
using File System Object, 676-677
from the Windows Registry, 615-616
x
x and y text boxes, 364
.xla files, 803-805
.x1s files, 445
XML
button, 741
overview, 585-587
XML files
reading, 587-594
structure of, 586
tracking row and column of celis, 595-
597
Xpath statement, 591
Z
zip files, 507, 508
Zoom operations, 182-184
902 I Index I
END USER LICENSE AGREEMENT FOR BENTLEY SOFTWARE
IMPORTANT - READ CAREFULLY: This End- User License Agreement ("EULA:') is a legal agreement between yo u (either
an individual or a single entity) and Bentley Systems, Incorporated ("Bentley") fo r the Bentley software and associated
documentation that accompanies this EULA, which includes the associated media and Bentley internet-based services
("Software").
YOU AGREE TO BE BOUND BY THE TERMS OF THIS EULA BY DOWNLOADING, INSTALLING, COPYING, OR
OTHERWISE ACCESSING OR USING TH E SOFTWARE. YOUR ACCEPTANCE OF ALL OF THE TERMS AND
CONDITIONS OF THIS EULA IS A CONDITION TO THE GRANT OF LICENSE BELOW. THIS EULA, AS MAY BE
MODIFIED BY ANY APPLICABLE SIGNED WRITTEN AGREEMENT BETWEEN YOU AND BENTLEY, REPRE-
SENTS THE ENTIRE SET OF TERMS AND CONDITIONS GOVERNING YOUR USE OF THE SOFTWARE AND
SUPERSEDES ALL PRIOR OR CONTEMPORANEOUS ORAL OR WRITTEN COMMUNICATIONS, PROPOSALS
AND PRESENTATIONS W ITH RESPECT TO THE SOFTWARE OR THE SUBJECT MATTER OF THE EULA.
If this agreement is translated into a language other than English and there is a conflict of terms between the English and the
other language, the English version will control. You should keep a copy of this EULA for your records. The latest version of
this EULA appears in its entirety on http://www.bentley.com/legal/eula_en.txt. Bentley may update or amend the EULA at
any time without notice to you; however, the form of EULA in effect at the time of the Software acquisition will apply.
1. CERTAIN DEFINITIONS.
1.1. "Academic Related Use" means the use of designated Software in obj ect code form solely for internal classroom
instruction or research of your teaching staff and! or students matriculated in a degree program and not to
include student use in a paid employment setting or any other use prohibited under this EULA.
1.2. ''Academic Software" means Software that is identified as "Academic Edition" or "Academic License" (or words of
similar meaning).
1.3. "CAe' means client access license.
1.4. "Device" means a single personal computer, workstation, terminal, hand held computer, pager, telephone,
personal digital assistant, Server or other electronic device used by a User.
1.5. "External User" means any individual (not an organization) who is not: (i) one of your full-time, part-time or
temporary employees; or (ii) agency temporary personnel or an independent contractor on assignment at
your place of business or work-site.
1.6. "License Key" means the document furnished to you by Bentley in electronic or such other format, as
determined in Bentley's sole discretion, that sets forth a unique serial number for the Software and authorizes
use of the Software.
1.7. "Production Use" means use of the Software in object code form by a single User or a Device, as applicable, solely
for internal production purposes in support of one Site.
1.8. "Site" means the discrete geographic location where you first install or use the Software.
1.9. "Time Clocks" means any time clocks, copy-protection mechanisms, or other security devices embedded in the
Software which may deactivate the Software after expiration of any applicable subscription or termed license
period.
1.10. "User" means any individual or entity that is not an External User.
2. GRANT OF LICENSE. As and for so long as you comply with all of the terms of this EULA, Bentley grants you the
right to (a) install and use one copy of the Software for Production Use in the country where the Software is first
obtained and (b) use the documentation that accompanies the Software for internal, non-commercial reference
purposes only.
3. RESERVED RIGHTS. You acknowledge and agree that the Software is a proprietary product of Bentley or its
suppliers, distributors and unrelated third parties ("Suppliers") protected by copyright and other applicable intellectual
property laws and treaty provisions. You further acknowledge and agree that the entire right, title and interest in and to
the Software including associated intellectual property rights, shall remain with Bentley or its Suppliers. This license
grant may be made by Bentley on behalf of Suppliers as third party beneficiaries of the license rights provided herein.
Bentley retains all rights not expressly granted to you in this EULA. THE SOFTWARE IS LICENSED NOT SOLD.
4. REGISTRATION. You acknowledge that registration or ac tivation may be required in order for you to utilize the full
benefits of the Software.
5. NO RENTAL OR COMMERCIAL HOSTING. Software is licensed for Production Use only. You may not rent, lease,
lend or provide commercial hosting services with the Software. You may also not use the Software to provide fee or
transaction based services. Contact Bentley for the availability of alternate pricing if you desire to use the Software in
such fashion.
6. NO "MULTIPLEXING" OR POOLING. Use of software or hardware that reduces the number of electronic devices
directly monitored or managed by the Software or directly accessing or utilizing the Software (sometimes called
"multiplexing" or "pooling" software or hardware) does not reduce the number of licenses required; the number of
licenses required would equal the number of distinct inputs to the multiplexing or pooling hardware/software "front
end:'
7. LIMITATIONS ON REVERSE ENGINEERING. You may not decode, reverse engineer, reverse assemble, reverse
compile, or otherwise translate the Software except and only to the extent that such activity is expressly permitted by
applicable law notwithstanding this limitation. To the extent that you are expressly permitted by law to undertake any of
the activities listed in the previous sentence, you will not exercise those rights until you have provided Bentley with
thirty (30) days prior written notice of your intent to exercise such rights.
8. DATA CAPTURE AND USE. You agree that Bentley may collect and utilize technical information gathered as part of
Software support services that may be provided to you. Data capture in this form will only be used to improve Bentley's
products and/or provide customized services to you and will not be disclosed or disseminated to third parties except in
an aggregated form.
9. ARCHIVAL COPY. You may make one copy of the Software on media appropriate for your single Device for the
express purpose of backup in the event that the Software media is damaged or destroyed, provided that you reproduce
and include on the backup copy all the information appearing on the original labels.
10. RESTRICTIONS ON CERTAIN SOFTWARE. Software identified as demo, evaluation, BDN, Beta or "NFR" (or "Not
for Resale" or with words of similar meaning) may not be sold, bartered or otherwise transferred. Such Software may
not be used for any purpose other than your testing or evaluation unless specified otherwise pursuant to a separate
agreement signed by both you and Bentley.
11. ACADEMIC SOFTWARE. For Academic Software, Bentley hereby grants you a non-exclusive right and license to use
in object code form such Academic Software for Academic Related Use only. You may not sell, barter or otherwise
transfer Academic Software. Special Note Applicable to Academic Software: If you have covered the Academic
Software subject to this EULA pursuant to a valid BEN SELECT Agreement (or successor agreement) with Bentley then
you may be entitled to additional and incremental licensing benefits to those set forth in this EULA by virtue of that
relationship. In the event that Academic Software is no longer covered by a valid BEN SELECT agreement due to
termination of the BEN SELECT agreement or any other reason, then you will lose those incremental benefits, and
your license rights will only be as set forth in this EULA.
12. TIME CLOCKS. Bentley's default licensing term is perpetual unless otherwise specifically identified for the Software
licensed. If you have licensed the Software subject to this EULA for a term shorter than a perpetual license, you
acknowledge that the Software may be delivered to you with embedded Time Clocks. You agree that Time Clocks are
not considered a defect of the Software and you release Bentley from any and all claims, however characterized, arising
from or related to Time Clocks or their operation.
13. TRANSFER. Internal. You may transfer the Software and the EULA to a different Device at the same Site, provided you
completely remove the Software from all prior Devices. You may also make a one-time transfer of a CAL to another of
your Users or Devices located at the same Site. In order to accomplish these transfers you may need to contact Bentley.
External. You may not transfer the Software and license granted under this EULA, or a CAL, to a third party without
Bentley's prior written consent. If such consent is obtained, you may permanently transfer the Software and the license
granted under this EULA, or the CAL, provided you transfer the Software and all and media to such third party, and
you do not retain any copies. The recipient of such transfer must agree to all terms and conditions of the EULA. Any
purported sublicense, assignment, transfer or encumbrance is void without Bentley's prior consent.
14. UPGRADES. You may not use any Software identified as an up grade unless you are properly licensed to use Software
which Bentley has identified as being eligible for an upgrade. After installing an upgrade, you may use the original
Software product that was eligible for an upgrade provided that at anyone time yo u use only the upgraded Softw are or
the prior Software version subject to the upgrade.
15. NO EXTENSION OF CAPABILITIES. You may develop your own applications that interoperate or integrate with the
Software. Bentley prices its Software, among other factors, based on capabilities that we expose to you. You may not
extend the Software to enable or unlock capabilities of the Software not specifically identified by Bentley as forming
part of the specified end user functionality.
16. SEPARATION OF COMPONENTS. The Software is licensed as a single product. Component parts of the Software
may not be separated and installed or used on multiple Devices.
17. TERMINATION. If you breach the terms and conditions of this EULA, Bentley may terminate this EULA without
prejudicing any of its other rights. In such event you must destroy and remove all copies of the Software fr om your
Device(s). Sections 1,3, 13,20,21,23,25,26,27,28 and 29 specifically survive termination.
18. NO AUTOMATED USE. A license for the Software may not be shared or used concurrently on different Devices, nor
to support multiple User or operational requests as indicated above. As a result, you may not use the Software in an
automated, unattended, non-interactive server application or component (including ASP) where: (i) multiple User
requests from different Users are queued for processing; or (ii) multiple requests from one User are queued for
processing but acting against content created or edited by other Users. Examples which would violate this Section 18
include but are not limited to use as a plot server, fi le translator, print server or other applications using or employing
similar methods.
19. LIMITED WARRANTY. Except for Software which is identified as no-charge, free, demo, evaluation, BDN, Beta or
NFR, which is provided to you "AS-IS" and specifically without warranty of any kind, for sixty (60) days from the date
of first installation (the "Warranty Period"), Bentley warrants that (i) the Software will perform substantially in
accordance with the functional specifications in the documentation which accompanies the Software; and (ii) the
media on which the Software is distributed meets generally accepted industry standards. It is understood that neither
Bentley nor its Suppliers are responsible for your use of the Software or the results from such use. It is furthe r
understood that there may be errors or omissions in the information contained in the Software, that the information
contained in the Software may not be current or complete and that defects in hardware or software may prevent you
from gaining access to the Software. This limited warranty is offered by Bentley alone, and is not extended to any
software code that may be contributed to the Software by our Suppliers. Any supplements or updates to the Software
(including but not limited to fixes, work in progress builds, or subsequent updates) provided to you after the expiration
of the Limited Warranty period above are not covered by any warranty or condition, express, implied or statutory.
20. DISCLAIMER. THE FOREGOING LIMITED WARRANTY STATES THE SOLE AND EXCLUSIVE REMEDIES
FOR BENTLEY'S OR ITS SUPPLIER'S BREACH OF WARRANTY. EXCEPT FOR THE LIMITED WARRANTY AND
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, BENTLEY AND ITS SUPPLIERS PROVIDE
THE SOFTWARE AS IS AND WITH ALL FAULTS, AND TO THE MAXIMUM EXTENT PERMITTED BY
APPLICABLE LAW IN YOUR JURISDICTION, BENTLEY AND ITS SUPPLIERS DISCLAIM ANY AND ALL
OTHER WARRANTIES, FOR ITSELF AND FOR ALL SUPPLIERS, EITHER STATUTORY, EXPRESSED OR
IMPLIED, INCLUDING, W ITHOUT LIMITATION, WARRANTIES OF GOOD TITLE, WARRANTIES AGAINST
INFRINGEMENT, AND THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE. THIS LIMITED WARRANTY GIVES YOU SPECIFIC RIGHTS; YOU MAY HAVE
OTHER RIGHTS, WHICH VARY AMONG JURISDICTIONS.
21. HIGH RISK ACTIVITIES. The Software is not fault tolerant and is not designed, manufactured or intended for use or
resale as control equipment in hazardous environments requiring fail-safe performance, such as in the operation of
nuclear facilities, aircraft navigation or communication systems, air traffic control, direct life support machines, or
weapons systems, in which the failure of the Software could lead directly to death, personal injury, or severe physical or
environmental damage ("High Risk Activities"). Accordingly, Bentley and its Suppliers specifically disclaim any express
or implied warranty of fitness for High Risk Activities.
22. END USER REMEDIES. If a defect in the Software appears that constitutes a breach of the above Limited Warranty,
Bentley shall, at its sole option, repair the Software, refund the price you paid for the Software or replace the defective
item(s), provided that: (i) you notify Bentley of the defect during the Warranty Period; (ii) the Software is not modified,
changed, or altered by anyone other than Bentley, unless authorized by Bentley in writing; (iii) your computer
equipment is in good operating order and the Software is installed in an officially supported environment; and (iv) the
non-conformity is not caused by a third party or by you, your agents, employees or contractors. Repaired, corrected, or
replaced Software shall be covered by this limited warranty for the period remaining under the warranty covered by the
original Software, or if longer, for thir ty (30) days afte r the date: (a) of installation by you of the repaired or replaced
Software, or (b) Bentley advised you how to operate the Software so as to achieve the functionality described in the
documentation. YOU AGREE T HAT THE FOREGOING CONSTITUTES YOUR SOLE AND EXCLUSIVE REMEDY
FOR BREACH BY BENTLEY OF THE LIMITED WARRANTY MADE IN THIS EULA. Outside the United States,
neither these remedies nor any product support services offered by Bentley are available without proof that you
acquired the accompanying copy of the Software from an authorized source outside the United States.
23. LIMITATION OF LIABILITY. Regardless of whether any remedy set forth herein fails of its essential purpose by law,
in no event will Bentley or its Suppliers be liable fo r indirect, special, incidental, economic or consequential damages,
regardless of the nature of the claim, including without limitation lost profits, costs of delay, interruption of business,
loss of use, costs of lost or damaged data or documentation or liabilities to third parties arising from any source, even if
Bentley has been advised of the possibility of such damages. In no event shall the liability of Bentley or its Suppliers
exceed the amount paid by you (in the currency used to purchase) for the Software. Some jurisdictions do not allow the
exclusion or limitation of implied warranties or limitation of liability for incidental or consequential damages, so the
above limitation or exclusion may not apply to you. THE PROVISIONS OF THIS EULA ALLOCATE THE RISKS
BETWEEN BENTLEY AND YOu. BENTLEY'S PRICING REFLECTS THIS ALLOCATION OF RISK AND THE
LIMITATION OF LIABILITY SPECIFIED HEREIN .
24. STATUTORY CONSUMER RIGHTS. Nothing in this EULA is meant to contravene statutory rights that consumers
may have pursuant to local law.
25 . EXPORT CONTROLS. The Software has been manufactured or developed in the United States of America and
accordingly may be subject to U.S. export control laws, regulations and requirements. Regardless of any disclosure
made by you to Bentley of an ultimate destination of the Software, you must not export or transfer, whether directly or
indirectly, the Software, or any portion thereof, or any system containing such Software or portion thereof, to anyone
outside the United States (including further export if you took delivery of the Software outside the United States)
without first complying strictly and fully with all export controls that may be imposed on the Software by the United
States Government or any country or organization of nations within whose jurisdiction you use the Software. The
countries subject to restriction by action of the United States Government are subject to change, and it is your
responsibility to comply with the United States Government requirements as they may be amended from time to time.
You shall indemnify, defend and hold Bentley harmless for any breach of your obligations pursuant to this Section.
26. U.S. GOVERNMENT RESTRICTED RIGHTS. If the Software is acquired for or on behalf of the United States of
America, its agencies and/or instrumentalities ("U.S. Government"), it is provided with restricted rights. The Software
and accompanying documentation are "commercial computer software" and "commercial computer software
documentation;' respectively, pursuant to 48 C.ER. 12.212 and 227.7202, and "restricted computer software" pursuant
to 48 C.ER. 52.227-19(a), as applicable. Use, modification, reproduction, release, performance, display or disclosure of
the Software and accompanying documentation by the U.S. Government are subject to restrictions as set forth in this
Agreement and pursuant to 48 C.ER. 12.212,52.227-19, 227.7202, and 1852.227-86, as applicable. Contractor!
Manufacturer is Bentley Systems, Incorporated, 685 Stockton Drive, Exton, PA 19341-0678.
27. GOVERNING LAW. This EULA will be governed by and construed in accordance with the substantive laws in force in
the Commonwealth of Pennsylvania. The state courts located in Chester County, Pennsylvania and the federal courts
located in Philadelphia, Pennsylvania shall have exclusive jurisdiction over all disputes relating to this Agreement. To
the maximum extent permitted by applicable law, the parties agree that the provisions of the United Nations
Convention on Contracts for the International Sale of Goods, as amended, and of the Uniform Computer Information
Transactions Act, as it may have been or hereafter may be in effect in any jurisdiction shall not apply to this Agreement.
28. SEVERABILITY. The provisions of this EULA shall be deemed to be separable and the invalidity of any provision
hereof shall not affect the validity of the remainder of this Agreement.
29. NOTICES. Please send all notices under this EULA to Bentley Systems, Incorporated, Attn: General Counsel, 685
Stockton Drive, Exton, PA 19341 -0678.
30. QUESTIONS. Should you have any questions regarding this EULA, please contact the Bentley subsidiary serving your
country, or write to: Bentley Systems, Incorporated, Legal Department, 685 Stockton Drive, Exton, PA 1934 1-0678 .
31. RE-DISTRIBUTION OF BENTLEY· VIEW- . If you are interested in re-distributing Bentley View either internally or
externally to your organization, please complete the online Bentley View Distribution Agreement fou nd at: http://
www.bentley.com/ bentleyview/ redistribute.html.