Professional Documents
Culture Documents
LEARNING
MICROSTATION"VBA
bV Jerrv Winters
Learning
MicroStation VBA
Jerry Winters
2006
LEARN I NG MICROSTATION
VBA
First Edition
Copyright 2006 Bentley Systems, Incorporated. All Rights Reserved.
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.
ISBN Number: 0-9714141-8-1
Library of Congress Control Number: 2006903498
Published by:
Bentley Institute Press
Bentley Systems, Incorporated
685 Stockton Drive
Exton, PA 19341
www.bentley.com
Foreword
John Gooding of Bentley Systems, Inc.
MicroStation VBA, the MicroStation V8 implementation of the
Microsoft Visual Basic for Applications (VBA) engine, provides
MicroStation users and developers with a large number of capabilities from easy customization to tight integration with other Windows
applications. With VBA, users can customize MicroStation to automate
repetitive tasks that are specific to their needs.
Many users have discovered the simplicity of using VBA to make their
jobs easier. The ability to use a standard user interface, the advantage of
using one of the most popular programming languages in the world, and
the ease of connecting and communicating with Microsoft Office and
other applications are just some of the many things that VBA provides.
While MicroStation VBA is popular, you might be among those who are
hesitant - perhaps even a bit leery - to explore programming in
MicroStation. You shouldn't be. VBA is the easiest environment to
explore programming, and Learning MicroStation VBA is an excellent
guide to help you do it yourself.
Too often, one-size-fits-all manuals lack either the appropriate
grounding material a new user needs or the in -depth technical
information experts require. However, Learning MicroStation VBA
accomplishes the rare feat of serving both novice and expert users
ii
I Foreword I
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
Introducing VBA ........................................ 1-1
What is VBA? . ... . ... .... . .... . ..... ..... . .. . .. . ... . . ..... . .. . 1-1
Why Learn VBA? ..... . . . . . . . . . . . . ....... . . ...... . .. .. . . .. .... . 1-2
When Should You Use VBA? ... ..... .. .. . . . . . . ..... . .. . . . ... .... 1-2
How Do We Use VBA? ... . .. ..... .. ........... ......... . .. ..... 1-2
What does VBA look like? .... ....... . . .. .... ........... . .. . . ... 1-6
Review .. ....... . . . . .. .. .. . .. ... . . . . .... . .... . .......... .. . . .. . 1-7
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
I Contents I
vi
I Contents I
Split and Join .. . .. .. . . ... . .. .. ... . ... .. . . .. ... . . .. . ...... . 7-95
Asc and Chr .......................... . ....... .. ..... . .... 7-96
FormatCurren cy .......... . ... . . . ................ . ........ 7-98
FormatNumber ........ .. ..... ... . ... ..... . .. .. ...... ... .. 7-98
FormatDateTime ......... . ... .. . . ........... . .. . .......... 7-99
Format ..... . ...... . ................................ . ... 7-100
& ...................................................... 7-100
vbCr. ................................................... 7-1 00
vbTab .................................................. 7- 101
Review .. . .. . ..... . ... . ......... . ........... . ................ 7-101
I Co ntents I
vii
viii
I Contents I
Events ................ . ... . .... ........... . ..... . ...... 10-161
ListBox .... .. .. . ...... ... ....... .. . . ....................... 10-161
Properties .............................................. 10-161
Methods ............................................... 10-161
Events ................................................. 10-162
CheckBox .................................................. 10-162
Properties .............................................. 10-162
Events . ....... .. ...... .. .... ....... ............. ....... 10-162
OptionButton . .... ......... ..... .. ......................... 10-162
Properties . ................... ...... ................... . 10-163
Events ................................................. 10-163
Toggle Button ..................... . ............... ... ...... 10-163
Properties .............................................. 10-163
Events ................... . ........... ................. . 10-163
Frame .... ... ........ ......... ... ......... ... .............. 10-164
Properties ... . . . ................... ... ...... ..... ....... 10-164
CommandButton .. ..... .......... . .......... ... ........ . ... 10-164
Properties . .... ... .. .. . .. ..... ...... ..... .. .. ..... . . . . .. 10-164
Events ................. . ............ ... .. . ............. 10-164
Tab Strip ....... .. .. ... .. . .. .. . ... ...... ..... ...... .... ..... 10-164
Properties ......... .... ........ ... ... ..... ......... .... . 10-165
Methods ............................................... 10- 165
Events .................... . . . . . ..... .... . . ...... ...... . 10-165
MultiPage ....... .. ...... . ....................... .... ... . ... 10-165
Properties .......... . .......... . ........................ 10-165
Methods .... ..... . . ... . . . ......... ........ .. . . .... ..... 10-165
Events . ...... .. .......... . ... .. ........... .. . . ...... ... 10-166
ScrollBar ....... . ...................................... .. . .. 10-166
Properties ............................ ..... .. ........... 10-166
Events ... ................ ...... ..... ................ . .. 10-166
SpinButton ........ ..... .................... .. .......... .. .. 10-166
Properties . .................... . ................ . ....... 10-167
Events ....... . ......................................... 10-167
Image ... . ...................................... . .......... 10-167
Properties . ............................................. 10-167
User Interface Exercises ............... .. .. . .................. 10-167
Point List Reader. ................................ . .......... 10-174
Write Out File .. ............................................ 10-177
Zoom And Pan .............. ..... ................... ....... 10-182
Review .................................................... 10-185
I Contents I
MicroStation VBA Help File . .. ... . . .. . . . . . . .. . ... .. . . ... .. .. . 11 -190
Adding Watch es ... .. ... .. . . . . . . . . . . . . .................. . . . . 11- 192
The MicroStation Object Model. .............................. 11-192
Application Object ...................................... 11-193
Review .................................................... 11-241
ix
I Contents I
Getting User Input ......... . . . . . ............... . ...... ... ... 17-334
Some Real-World Applications ....... . ....................... 17-338
Using SendCommand . . . ... . . . .. ... ....... .. .. . .. .... .. .... . 17-348
Modeless Dialog Boxes ................... . ..... . .. . .. . ... . ... 17-353
frmMatchProperties.frm ............. . ................... 17-353
Providing User Feedback and Information ..................... 17 -359
UserForm Initialize ...................................... 17-360
frmAlignText.frm ....................................... 17-362
frmExportElements.frm .................................. 17-377
frmDFAV.frm .......................................... 17-381
Interacting with MDL Applications ............................ 17-387
Review ..................................................... 17-390
I Contents I
xi
xii
I Contents I
The ChangeAttribute Event .................................. 25-536
Review ..... . ...... . .............. .. ... . ................... 25-536
I Contents I
xiii
xiv
I Contents I
Using Third Party ActiveX Controls and DLLs .......... 33-667
Using ActiveX Controls ...................................... 33-667
Using Existing DLLs ......................................... 33-670
Microsoft Scripting Runtime ............................. 33-674
Microsoft Speech Object Library .......................... 33-679
Microsoft CDO for Windows 2000 Library ................. 33-680
DSO OLE Document Properties Reader 2.0 ................. 33-681
Review .............................................. ... ... 33-688
I Contents I
xv
xvi
I Contents I
Accessing ASCII Files .................................... 39-868
Traversing a Folder and its Subfolders . ......... . .......... 39-870
Getting All Files in a path ............................. . .. 39-87l
Returning Function Values ............................... 39-872
Windows API Calls ...................................... 39-872
Distributing VB.NET Applications ............................ 39-877
Review ............... ......... ............................. 39-880
Introduction
Learning MicroStation VEA provides an in-depth tour of one of
MicroStation's most powerful customization abilities. The book starts by
supplying the foundation for understanding VBA basics and then shows
how to apply the fundamentals to real-world situations.
Learning MicroStation VEA provides full coverage of the VBA subject taking you through the basics like the editing environment, modules,
visual interface, and MicroStation object model through advanced
topics like the Windows API, interacting with other applications, and
Visual Basic, among many other things.
Whether you are a MicroStation user who simply wants to make your
job easier or an experienced programmer who wants to master the
nuances of MicroStation VBA, this book is an invaluable resource for
learning MicroStation VBA.
The following type styles are used in this book to distinguish various
text:
Filename or URL
Fu nct io n
Object
Fu nctionlndex
Variable
Keyboard key
xvii
xviii
I Introduction I
ACCOMPANYING
CD-ROM
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.
I Acknowledgments I
xix
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
Introducing VBA
"LET'S START AT THE VERY BEGINNING. IT'S A VERY
GOOD PLACE TO START."
[B What is VBA?
[B Why should we learn it?
[B When should we use it?
[B How do we use it?
[B What does it look like?
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.
VBA?
Named GrO!:J)s
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
UDkQ.c!~.J!lyqiL_______
Inlroduction.mvba
Directories:
D:\MVBA Files\
~D:\
~ MVBAFiles
This loads the .mvba file into MicroStation and displays it in the VBA
Project Manager.
Default
Introduction VSA Introduction
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.
When you click it, the Macros dialog box opens, which allows you to
select which macro (procedure or function) you want to run .
. Run
. Cancel
Module1.PlocedureA
Module1.ProcedureC
Delete
.1
.wI
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
'********
I Review I
:: X" : I
: ~ :z":1
:::::z" :!
!I' !.
li t
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.
projects.
[8 The Project Manager allows us to run the procedures and
file name.
[8 Enter the Visual Basic Editor from the Project Manager.
[8 Record macros from the Project Manager.
[8 Auto-Load VBA Projects so projects are loaded each time
MicroStation is started.
9
10
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
You are prompted for the location of the new .MVBA file
and for its name.
Open an Existing
VBA Project
Save Project As ..
All saved VBA projects and new projects are edited from
within the VBA Editor.
11
Run Macro
Record Macro
Stop Recording
Macro
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
Box
We use the Macros dialog box to select a macro to run but we can do far
more in this dialog box than just running a macro. We can "Step Into" it.
Mac[oname:
Run
lii'U.
ProcedureA
ProcedureC
Macros in:
I
I
I<All- Standard
. ...- Projects>
_---_
_._.... -_._.....
........
............-.- ..
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
We have covered every button in the Macros dialog box except for one,
the button that is grayed out in the image above. You use the Create
button to create new Macros. It's simple. Here's how it works:
As you select macros in the Macros list, a TextBox just above the list box
displays the macro selected name. If you change the text in the TextBox
to a macro name (Procedure name) not already shown in the Macros list
box, the Create button is enabled to begin a new macro with the name
specified. So, if you type ProcedureA_l into the TextBox and click the
Create button, a new Procedure named ProcedureA_l is created. Of
course, no code is entered into the procedure after it is created. That is
our job. We can now select ProcedureA_l from the ListBox, click the Edit
button, and go into the new procedure in the VBA Editor to begin
writing code.
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
Menus
[8
Toolbars
[8
Windows
1S
16
i E.ila
gdit
S!jew
insert
FQ.r(llat
Q,ebug
&un
Iools
8ddlns
~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
imports existing
form (.frm), module (.bas), and
class (.cls) files into our project.
[B Import File
w;]
l! import File ...
r;;Xport File .. ,
Ctrl+M
Ctrl+E
Remove
exports forms,
modules, and classes from our
~Iose and Return to Micro5tation Alt+Q
project to their own .frm, .bas,
and .ds files. After these files have been exported, they can be
imported into another project.
gj E,rint .. ,
Ctrl+p
[B Export File
[B Remove
I Menus I
17
Edit Menu
[B Undo and Redo are standard
;1 Can'l: Und"
,;
,f,
I ~()
11.8
objects.
Ctrl+Z
Can't Redo
':ut
,: ttl+X
~opy
Ctri+C
e.'~$ bE!
Ctrl+v
Clear
Del
Select all
Ctrl+A
~l ::~:'~;ext
,:trl:
,l R~DI~~8' "
CtriHi
, i -,.--,-,---,--,--,-,,------,-,,--t:~1 ~ndent
Tab
~~lj ~~~
__~hift:Tab _
Ctrl+ J
Ctrl+Sh,ft+ J
Ctrl+1
Ctrl+Shift+1
Ctrl+Space
I ~ookmarks
cursor is over.
[B Complete Word shows the list of Constants and Methods in
18
View Menu
:rifI:
~ode
I~
OWect
F7
Shift+F7
~efinition
Shift+F2
Last P05itio!l
Cttl+Shift+F2
~ Qbject Browser
in'
[mmediate Window
Local~ Window
&}'
Watch Window
Call
Stac~" .
~. E,roject Explorer
~, Properties Window
"~ TOolbO~
,
F2
Ctrl+G
Ctri+ L
Ctri+R
F4
Tb Order
Ioolbars
3. MicroStation
Alt+FIl
I Menus I
19
Insert Menu
[B Procedure displays the Add Procedure
rnsert '--_ __
~j ~~::::~:e . .
Module
~I =Iass ~lodule
'-Ile ...
Format Menu
8!ign
Make Same Size
'X 'f
Size to
Fi~
Size to Gri!J.
tlorizontal Spacing
Ilertical Spacing
~enter
in Form
~.
.roup
!fl
klngroup
Qrder
Debug Menu
Compile Default
c:;]
Step into
l:ll
St~p
c!-=
StepOl,!t
-"
Qver
F8
5hift+F8
Ctrl+5hift+FB
Ctrl+F3
add Watch .. .
~dit
6d
W.,tch .. .
Quick Watch .. .
ctrlHV
Shift+F9
;$,
Ctrl+Shift+F9
Cl:rI+f9
20
Run Macro
UJ
8rea~
F5
ctrl+8reak
la
B.eset
III
Design t10de
Tools Menu
IB References allows us to add a
reference to existing DLLs and type
libraries. For example, if we want to
work with Microsoft Excel, we can add
a reference to the "Microsoft Excel
Object Library". Doing so makes
working with Excel in VBA very easy.
~ B.eferences ...
ill ' additional Controls ...
t1acros ...
'i - - - - --1
Qptions ...
t
,
Def ault
Prop~I'ties .. .
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. Addins can be loaded based on the "Load Behavior" settings.
-------------------:---------------!
Available Add-Ins
'
Stait~p 11];;r;,~ded-'
OK
Cancel
L -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_____._____
. _ ________ _
Add-In created for MicroS tation VBA
.A !
.g,~sc lipti on
~: ~[
- tl-elp- - '
::.J ["oadcd/lJnio.,ded
CJ Lo~d on 5.1altup
.. ........-- .... ,)
Window Menu
~.Jiti9=
'H_.ll_ _ _--,
SQ.i,t
Tile tiorizontaliy
Tile 'lerticaliy
hascade
~
8,rrange Icons
Help Menu
!B We will cover Help issues in the
next chapter. One way to get there
is by clicking the Microsoft Visual
Basic Help menu item.
F1
22
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' ~
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
Edit menu.
~i~,,-~~,"~ili~~1:!1I; ~~J~A~"
Debug toolbar
The Debug toolbar displays the functionality found in the Debug menu.
I Windows I
23
UserForm toolbar
UserForm
"1 J:) ~
... .
0(: ,i."
\ ~ ;"';,T
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
L... EID UserForm!
8"es Modules
:
\.. ~ Module!
a. @j Class Modules
'. '@I m!D1
;....@1 Class!
;.~ Module!
; .. I UserForm!
24
Classes
(; <g lobals>
@J Ac cuDrawHints
@J ACSManager
@J Application
@J ApplicationElement
@J App licationObjectCo
@J Arc Element
@J AreaPattern
@J Atta chment
@J Attachments
ActiveDes ignFil e
ActiveMode lReference
ActiveWorkspace
AddAttachmentEventsHand ler
AddChangeTrackEventsHandler
AddLevel ChangeEventsHandler
AddModalDialogEventsHandler
AddMode lActivateEventsHandler
I Windows I
25
Properties Window
Objects in VBA have names. For
example, this user form has the name
UserForm 1. We can use the
Properties window to change this
form's name, color, and other
properties. The Properties window is
used extensively when working with
forms and controls on forms.
Watch Window
UserForm1.Cornrnand8utton1_Click
DesignFileJDesignFile
UserFonn1.Cornrnand8utton1_Click
ModelReferenceilvlodelReference UserForrn1 .Cornrnand811tton1_Click
ActiveWorkspace
Settings,Settings
UserForm1.Cornrnand811tton1 _Click
WorkspaceNVorkspace
UserForrnl .Cornrnand8utton1_Click
UserForrn1 .Cornrnand8utton1_Click
UserForm1 .Cornrnand8utton1 _Click
UserForm1 .Cornrnand8utton1_Click
UserFonn1 .ComrnancI8utton1_Click
Long
UserForm1.Cormnand8utton1_Click
CursorlnforrnationiCursorlnformati UserForrn1 .Cornrnand811tton1 _C lick
ObjectN8Project
UserForrn1.Cornrnand811tton1 _Click
"C:'Prograrn I String
800lean
HasActiveDesign True
H asAct iveMode l~
800lean
Long
FuliNarne
Height
True
1201
UserFonn1.Cornmand8utton1_Click
IsAcadernicVersi, False
800lean
UserForrn1.Cornrnand8utton1_Click
UserForrn1 .Cornmand8utton1_Click
IsCeliLibraryil.ttac False
800lean
UserFonn1.Command8utton1
26
DesignFilelOesignFile
ModelReferencelModelRefen
SettingslSettings
WorkspaceNVorkspace
No cell library>
CeliLibrary
Bsplinefaspline
CadlnputQueuelCadlnputQue
"chapjer03.dgn (2D -
va Dor string
CommandstaielCommandstal
CurrentOraphicOroup
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
I Windows I
Learning
~1icroStation
VBA
27
in the Immediate window and press the <Enter> key. When we do so, a
MessageBox displays.
~
Show
'.1
Close
Toolbox Window
The Toolbox window displays the standard
controls that can be placed on our user
forms. It only displays when a user form is
the active window in VBA. If we are working
with a user form and the toolbox is not
visible, click on the Toolbox icon in the
Standard toolbar or go to the View >
Toolbox menu to display it.
1
~ Aabl~1ffiI
Controls
P(o';::!L1-l
..!..l:..:J ~.!l~
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~ I
Editor Format
r Docl<3ble -
---
I ~ii~iii:~~i~t.i.Wi6~9.0.:
I ~ L.ocals Window
I ~ ~atch Window
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.
Here is a Form.
CommandButton I
----....---.-1 __,_,_,._,,_,_
..
.....
0;
'
...
. ... .
.
...
. . ., .. . .. . . .
- . ... . . . . . . . . .. . , ... ... . , . .. . . .
. . . ,. . .. ..
.... . . . . ., . .
. ... . . . . . .
... . , . . . . .. .. . . . . ..... ., .. .... ..
.... , ...
.
, '-
I Windows I
29
Event of
CommandButton 1.
View
30
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.
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
32
---~
----
---
- -
--
---
---
"
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
34
Hide
Locate P;eviou ~ ~iext
Back Forward Stop
Refresh Home
-~---------'-----",---'----------------:""'I: I
- -
Visual Basic
~ ~
~ Visual Basic Conceptual Topics
Visual Basic HowTo Topics
Visual Basic Language Reference
Visual Basic Addln Model
~ Microsoft Forms Reference
ttl.
tt ll .
Set'3.t\J::;O
1il
Specifit;:s
. !I'
I
I
.'
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
Hide
[iJ
if
{l,
<?
s>
.,
[1J
Jt.
Locate
Pr>;:.j!Cri.;~
N'::-i!t
Back
Forward
Stop
Refresh
Home
Font
().,
~o';ients I Index
I Search I Favorjtes I
id
ComboBox Control
Se e Als o
Exam pl e
Properties
~I etho d s
;~
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~
[Itext
CompareMode property
Filter function
InStrRev function
Replace function
Split function
wildcards
string conversion
String data type
String function
String keyword
String$ function
strings
aligning
character
comparing
concatenating
converting
data types
fixed-length
formats
iustifying
leftmost characters
length
manipulating
matching
middle characters
removing spaces
repeating
replacing
returning from functions
clearing
color
comparing
converting
culling and pasting
entering
from numbers
importing
looping
searching/replacing
5 tring data type
text files
inserting
TextStream obiect
The binary compatibility DLL or E>
The binary compatibility DLL or E>
Then keyword
This (Me keyword)
Tile Horizontally command
Tile Vertically command
Time function
time intervals
adding
difference
Time keyword
time stamp
Time statement
Time$ function
Timer function
~!
timer s
reversing
times
adding
converting
creating
Date data type
determining
rightmost characters
searching
spaces
substrings
variable-length
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
Search tab
19.!:l!.e:ntslli:d . Search
lli.~~r!~e.~J
1- [ list Topics
ComboBo~ Control
Toolbox
Unable to unload withi ...
Understanding Obieet. ..
; MatehF ound. MatehR .. .
I Layout Event, OldLeft .. .
Style Property
I DblCliek Event. CanP ...
ComboB ox Control. A. ..
Ways to put data in a ..
! list Property
Things you can do wit. ..
, Style Property Example
MatehE ntry Property..
AutoTab Property
BoundColumn Property
Text Property
CurX Property
TextColumn Property
, Value Property
Locked. DropButtonS ...
DropDown Method Ex. ..
DragBehavior Property
ListWidth Property Ex. ..
ListRows Property EK ..
, lineCount Property
! Add items to a list usin...
Listlndex Property
I ListStyle Property
I
I
,
I
I
I
o Search previous results
Mrerosolt Fa...
Visual Basic ..
Visual Basic..
Visual Basic ..
Microsoft Fa...
Microsoft Fa.. .
Microsoft Fa .. .
Microsoft Fa .. .
Microsoft Fa.. .
Microsoft Fa ...
Microsoft Fa .. .
Microsoft Fa.. .
Mierosoft Fa...
Microsoft Fa .. .
Microsoft Fa .. .
Microsoft Fa .. .
Microsoft Fa .. .
Microsoft Fa.. .
Microsoft Fa.. .
Microsoft Fa.. .
Microsoft Fa .. .
Microsoft Fa.. .
Microsoft Fa .. .
Microsoft Fa.. .
Microsoft Fa .. .
Microsoft Fa .. .
Microsoft Fa.. .
Microsoft Fa...
Microsoft Fa .. .
Display
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Favorites tab
~
Hide
Locate
it
r~it.!;\';[';l.l~
~l
~h;'.t
<?
Back
Forward
Stop
ITl
Refresh
Home
J[,
Font
----------'--"-----'-'-'-'---'--"--'--"----'-':'-n- - - - - - - - - - - - --
Tallies:
-.">.I
,
to
See Also
In a ListBoK or (1I'ttfijifi]:litft with a single co lu mn,
I"
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 Help Fi les I
39
riJ
to.
'?
I::;>
Bxk
F'Jrh!,:'hi
m1r.
.----.. -.-.-. ------..-.--.-.----.-. ----.-. -.-.- .-.- . -..--.-.-- . . . . . -.----.-.--.. . -- . _-_ . _ . __. _ . . . __. 1-.---------".-.
Hide
Locate
!;ontents
Plint
Qptions
,;:
II-licroStation V8
Visual Basic for
Applications
8 ~~
8
rl
CJ
FtJ (j Enums
Lt! G:iJ 0 bjects
rl CJ Events
rl CJ Methods
if ] CJ PlOpelties
rl (] Types
C':::::\ C ............... I.........
MicroStation has its own VBA Help file. It contains MicroStationspecific help for VBA. Searching for the file 'microstationvba.chm' on
your computer should show us where it is and let you open it.
-r"'"--';~-.r-,..,'--'l"
..'r.-.,.....,r:'.
--::""",-~--"""~",,..,..,,,.~.~",,,,,
N.",<_~
></<~--~~'Z"""""Y"l".,.,.,~,,,,,,,,..,.,,'
Ili},M!craSla!ianV.8,Vi~ua!Basi~,f~~~llpl!cali~ns, I:f'tlp
s;
[li]
<?
~
Hide
Locate
Back
,--' -"'-'"
~_
.. ,.. ..
-~
___
__
,';
Y_~_~"_
~[9]~
FCO;'Nl'l:d
38
_.'~"_'V
~,'
[,amples
~ Accessing an Element's Vertices
00
ill
[I Alcs By Length
Area Booleans
~ :',,_~;~: :=_:-~=:~':;;,;r,'::~_:::~;~":':.~__
',I
>.
,~1,:
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
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.
"='"
\lj~ttI .hfie
~lllh:,l;iQfl1 (Ve.I\) ,oftw. ~, .... ,IQ~~nt kJt (~I<) 'fI.b!.f ~'I\,.P{~~tl\t'f~kw .. r ""Mo,.,
(l5V'J) too ~a."h(IO ,(I,.rt.enfl1\ty tG t:h/J'lr ,'CDhe{lhcnj with Ute nrflmler'nJ~ClYIj"'lbon IDE Md the: Mo(tOt<lttVL.11J.a1 e.Ule
n,
E2!Jill'!i.
'"~""d ,,,I"'.f'ql"U~
..
GIi!
)'OUfS
itud ~lJl,ItU"J
lotl.ay!
'~l n ;t~bd.,.lJl.f:.tll'.tj!
I~Q~Q""
; CcIl'o)~tU-"
, f .t H " ite ~itir;orlt .n)j
clitHlda l\lbl'l'tlS~JH
rur epllliNti!i'tl
hpl"",,,
t!cto1lng ytiA
Lici-nlin9 \'0~ .oMbl"" yeu to
~MtrlbM
yOLOr vu.,.
hdrWU' ,,,,:'Yyrt
( P C VIlA
a..,.."
V.eA 4,'.
j)tIt'J:J!!\.XQMIlU.Y..lJI.~,IL'U .Q
wn
Lt~.U.I!I.Q..,eArtntli
pr(llflJtt~
~t. ", .. rt
YM :CO$'
'!:4 "J "J ~~ 1"''' i' " .i:'~$ TMI~ I~ ... ~Hi~~.
(;o.n.... rt lOad, 'r))O'\ '1isulIl ouic k.r APpliGafl('nf" to 'Ils\llIl
'!'Ii:;
e ,'.po'''t
~
u!l.~A.'(I..t$..Stt.lIl:J!!J.tJlt\:' ~i.U l1n.o..er.'tt'OJ Ctt
:Il~!UlJl~R4.t.'~~ ~~l1>J:P.I.lltM)
I The Net I
41
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?
Login \ Site Map ! PI illt i Stor e
~BENTLEY
~{markets
Search
1vlicroStation.
Bentl ey I Develooer Resources Over .... iew
Among
Ptl'J<lCY
the
Bentley
Discussion
Groups
we
find
Bentley.microstation.v8.vba. This is a good place to ask questions. And
who knows? As you become a VBA guru in your own right, you may be
42
~dit
Eile
~ Back
~iew
T
t}
Fgvorites
T
lools
tielp
.~. ~Go
iLinks
~BENfLEY
ft'Onl
a newsre.3der? Go to Bentley.testposts,
NicroStation
Bentley ,rnicrostation .'18 .xme.3rlyacce$$ (new)
Benti",,, ,rnicrostation .'18 .gener.~1
Bentley .rnicrostation ,v8 ,d'.NQ
43
displays its properties, metho ds, and events m the listbox on the right
side of the window.
-
Object Browser
'
vI '" ~
'---------'
Cla sse s
" : I1i'
_ 11i'
I1i'
I1i'
I1i'
Gl <global s>
li!'J AccuDrawHin ts
li!'J ACSManager
li!'J 'Appiication-
ActiveMode lReference
ActiveSettings
ActiveWo rkspace
Appli cation Objec tConnec tor
.,~ AddAttachm entEventsHandl er
Arc Element
"~ AddChangeTrackEve ntsHand ler
AreaP attern
" ~ AddLeve lChangeEventsHand ler
Attac hmen t
"'~ Ad dMod alDialogEventsHandler
Attac hments
;~ Add Mo delAclivate Eve ntsHa ndler
.,~ Ad dMo delChang eEventsHand ler
Auxili aryCoo rdinateSystemE lemer
8s plin e
,~ Add SaveAsEventsHa ndle r
.. "~ Ad dViewUpdateEve ntsHa ndler
8s piin eCurve
,.~ Appen dXDatum
8 sp iineCurveElement
8spiineSurfa ce
."~ ApplyHorizonta lScalingFixForEMF
v ~ .o:.~ AnnhMprti (';:. I~(' ~l i nnj:" ivj:" nrI=MJ='
R c: n li n p !=:l l tf~ (' p l= lpmpn t
~ 'APpiicaiionElemeni'
~
ti:I
ti:I
~
~
li!'J
~
li!'J
~
ti:I
ffl
ACSManage r
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...., ,..
~ .~
:::
.........................................
Classes
:.~
i..>
AttachColorTable
Au thor
~' 11i' Client
. ,~ Close
ti:I
i!J
i!J
ti:I
ti:I
ti:I
ti:I
;ef!
Co neElemen t
CopyCo ntext
CrossHatc hPattern
Cu rso rlnformation
CurveElement
Da tabaseLi nk
Data8 10ck
DataEntrvRegion
.:JiOesignFiie
ti:lOlme'nsi;;;;Elemeni ' .
",~
. I1i'
I1i'
I1i'
Commen ts
Company
Cu stomP ropertyExists
I1i' Date Created
I1i' DateLastPlotted
I1i' DateLastSaved
I1i' DefaultModelReference
"~ DeleleLevel
I1i' Dimens ionStyles
.,~
'
mDimensionStyle
i!l
DimensionStyles
;ef! DLong
~.~ nrnnn::lhlp l= lprnpnt
I1i'
y) .0<'\
Editor
l= }(fr:::lr trnlnrT :::I h lp
44
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.
Modules
[B
Forms
[B
Classes
[B
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
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
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
milliseconds, we can draw this target by
running the macro Ma in whenever we
wish.
The more
hard-coding
we do, the less
often we will
be able to run
our macros.
. I
:I
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
Ma i n3 with different coordinates, then Ma i n4, then Ma i n5 and so on.
Right? Well, we could do that but there is a better way.
Let's change the way we are doing things a little bit. Instead of having
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 DrawTarget (CenX As Double , CenY As Double , CenZ As Doub l e)
' Declare Variables
Dim MyLine As LineElement
Dim MyCir As EllipseElement
48
Appl i cat i on . Act iveM ode lRef e r ence. Add Elem ent MyLine
' Create Ci rc le s
CenPt . X CenX
CenPt . Y = CenY
CenPt.Z = CenZ
Set MyCir = Application.CreateEllipseElement2(Nothing. CenPt._
0.25 . 0 . 25. RotMatrix)
Applicat i on.ActiveMode l Refere nce . AddElement MyCir
Se t MyCir = Appl ication.Creat eEllip se Ele men t2 (Nothi ng. CenPt._
0 . 5. 0.5. Rot Mat r i x)
Application.Act i veModelReference . Add El ement MyCi r
End Sub
The code from Main has been copied and pasted into the same code
module. The new pasted procedure is then renamed DrawT arg et. The
goal here is to make our code more flexible, so we can draw targets
anywhere we specify. Our new procedure, DrawTarget. requires us to
specify three parameters named 'CenX', 'Cen Y', and 'CenZ'. We declare
them as doubles (very precise numbers). Let's take a look at how we
use it.
I Forms I
49
Sub Ma in ( )
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
We can also
get here by
right-clicking
on the button
and selecting
View Code in
the pop-up
menu.
the button when we are designing in our project to be taken into the
eli ck Event of the CommandButton.
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 ()
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
The macro named
Ma i n that is shown is
the procedure Ma i n.
When it is selected,
click
the
Run
button.
The
form
is
displayed so we can
enter numbers for X,
Y, and Z coordinates
to place our targets.
S1
Macro name:
Main
'
"
"
,
Step Into
Edit
Macros in:
[----------------::::1
<All Standard Projects>
v,
Delete
IDescription:
Before we continue,
let's review what we have done.
We wanted to allow our users to draw a target symbol inside
MicroStation. The first thing we needed to do was write some code to
draw the target correctly. So we put our code in a procedure named Main
and got the basic code that draws a target shape working by hard-coding
everything. When that code was working properly, we made the code
more flexible and useful by taking the code out of Ma i n and creating a
new procedure named orawT ar get . We provided three parameters that
could be used to specify the location of the target. After all of this work
was completed, we tested it by modifying the code in Ma in to use the
Procedure named or awTa rget.
The next step was creating a user interface (more on using forms in
Chapter 10). We used the values from the text boxes for the parameters
of orawTa rget (converting the values from a string to a double by using
the standard VBA COb 1 function) . The last step was to change the code
in Ma i n to display the form.
We now have a code module and a form working together using ~l a in to
display the form. When the user clicks the button, values from the form
are parameters in orawTarget, which resides in the code module. So,
why is orawTarget in the code module? Couldn't it be in the code area of
the form? Yes, it could be and the code would still work. However, other
modules and other forms would not be able to use orawTa rget as easily if
it had been placed in the form's code area. One of the things that makes
a code module so great is that declared procedures and functions can be
easily utilized in other areas of our project. We may have three forms
52
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
=X- 1
LineSt.X
LineSt.Y;::: Y
LineSt.Z '" Z
LineEn.X
LineEn.Y
LineEn.Z
X + 1
Y
Z
=
=
Set MyL ine = App 1 ieat ion. CreateL ineE lement2 (Nothing,
App l icatlon.ActiveHodelReference,AddElement MyLine
L ineSt,
L ineEn)
LineSt I
L ineEn)
LineSt.Z =
LineEn.X =
LineEn . Y =
LineEn . Z:c
Z
X
Y - 1
Z
CenPt.X
CenPt . Y = Y
Ce nPt. Z :a Z
Set MyC i r = Application . CreateEllipseElement2(Nothing. CenPt.
App l i c ation . Act ive llode lRefer e nce . AddElement MyC i r
Set MyC i r = App li cation . Cr eat e El l i pse Element2(Noching. CenPt,
Appl i cation , Act i veMode lReference , AddEl ement HyClr
0 . 25. 0 . 25.
RotMatrix)
End Sub
S4
0 . 5, 0.5, RotMatrix)
Application.ActiveModelReference.AddElement MyCir
End Sub
55
<
S6
57
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
Sub TestDrawCircle3 ()
DrawCirc le3 2 .25, 2 . 2 5, 0
DrawC ircl e 3 2 . 2 5, 2 . 25, 0, 1.1 25
DrawCi rcle3(X As Double. Y As Double, Z As Double, [Radil/s As DOl/ble= 1.25])
End Sub
58
= Application.CreateEllipseE'ementZ(Nothing, CenPt, _
We don't know how many radius values will be provided in the Radii
ParamArray. So, we use a For ... Next loop which allows us to look at
each one and use it in creating a new circle. Here is an example of how
we call a procedure with a ParamArray in code:
Sub TestDrawCircle4 ()
DrawC i rcle4 1. 1, 0 , 0 . 25 , 0 .5, 0 . 75, 1. 1.25 , 1. 5
En d Sub
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.
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).
Function RTO (AnglelnRadians As Double) As Double
RTD = Angle l nRadians * 180 / Pi
End Func t ion
Function OTR (AnglelnDegrees As Double) As Double
DTR = AnglelnDegrees * Pi / 180
End Function
60
Create ArcE l ement2 requires several parameters. One of them is the Start
Angle. Another is the Sweep Angle. Both parameters require the value
to be given in radians. Many of us don't normally think in radians, we
think in degrees. So, we can use the DTR function shown above to convert
from degrees (which we think in) to radians (which the function is
expecting).
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
underscore
C) character
allows one
line ofcode to
span multiple
lines.
61
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
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.
Funct i on Po l arPoint2 (X As Doub l e , Y As Double , Z As Double,
Angle As Do uble, Distance As Doub l e) As Point3d
Dim XC hange As Double
Dim YChange As Double
XChange = Cos(Angle) * Dista nce
YChange = Sin(Angle) * Dista nce
Dim PPoint (O To 2) As Double
Pola rP oint2 . X X + XChange
PolarPo i nt2 . Y Y + YChange
Polar Poi nt2 .Z
Z
End Fun ction
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.
Functi on GetExcelWS ( ) As Object
Dim Exc el App As Obje ct
Se t Excel App = GetObje ct ( , "E xcel. Appli cat ion " )
Set GetEx celW S = Exce l Ap p . ac t ive s heet
En d Funct io n
This function gets the active worksheet in Microsoft Excel. Excel must
be running for this function to work correctly. How do we use it? Let's
take a look.
Sub Te s tGetE xcelWS ()
Dim MyWS As Object
Dim Ce 111 As Doub l e
Dim Ce 112 As Double
Dim Cel13 As Double
Set MyWS = GetExcelWS
MyWS.Range( "B2 " )
Ce 111
MyWS.Range( "C2")
Ce 112
MyWS . Range( "D2")
Cel13
End Sub
64
Y= 2
Z= 3
End Su b
This procedure accepts three parameters. Inside the code, we use the
parameter's names and assign values to them. It is important to
understand this is because using variables directly in this manner will
change the values in the function or procedure that calls this procedure.
Sub TestGetThree Vals ( )
Di m A As Doubl e
Dim B As Dou bl e
Dim e As Dou bl e
A = 100
B = 200
e = 300
GetThreeVals A, B, e
End Sub
65
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.
Y 2
Z 3
End Sub
66
I Review I
67
4. 5
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.
When we attempt to run the macro test shown
above we get an error.
Compile error:
oK m )i [
Help
REVIEW
[B Write code as procedures, functions, or inside user form events.
[B In procedures and functions utilize required and optional
parameters.
[B In functions you can return values, arrays, types, and obj ects.
68
[B
Variables
1+N+3=7
In this chapter:
[B
[B
[B
[B
Arrays
[B
Constants
[B
Variable Names
[B
Option Explicit
[B
Using Variables
69
70
I Chapter 6: Variables I
STANDARD VBA VARIABLE TYPES
A variable is a name that represents a value or an object. The examples
above show variables with a name of N. In one instance the variable
holds a numeric value. In the other it holds a string of characters. In
general, we know in advance what type of value or obj ect a variable will
be representing. Since we know this, we specify what type of variable we
will use by declaring it.
Dim N as I nteger
N= 7 - 3 - 1
" I S"
MsgBox "L earning Mi croStation VBA " & N & " Easy ."
Integer
Di m PageNumber as Integer
PageNumber
Long
Dim MySalary as Long
MySalaray
123456
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.
Sub Vari abl eTestC ()
Dim N As Doub l e
N
1.23456789012346
12 . 3456789012346
1234 . 56789012346
12345 . 6789012346
123456 . 789012346
1234567 . 89012346
12345678 . 9012346
123456789 . 012346
1234567890 . 12346
12345678901 . 2346
72
123456789012.346
123456789 0123 . 46
12345678901234.6
End Sub
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
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
73
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
[B
[B
[B
[B
[B
74
Application.ActiveDesign File
[8
[8
[8
[8
ModelReference
Di m MyM odel As Mode l Refe r ence
Set MyM ode l
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)
Description
[8
ElernentColor
[8
ElernentLineStyle
LineElement
Di m MyLine As Li neElement
Set MyLine
EllipseElement
Di m MyC i rc l e As El l i pseElement
Dim Rot Matr i x As Matrix3d
Set MyCircle
CreateEllipseElement2(Nothing.
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. _
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
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.
"Easeme nt"
Di m EasementLeve l As Level
Set EasementLevel =
Act i veDes i gn Fi 1e . Add NewLevel (L evel Name)
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
My Ve r tic i e s ( 0 ) . Y
My Ve r tic i e s ( 0 ) . Z
My Ve r tic i e s (1
MyVerticies(l) . Y
MyVerticies(l) .Z
Set MyLine
) .
CreateLineElement1(Nothing . MyVerticies)
78
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.
I Variable Names I
79
Based on the rules already identified, here are a few variable declarations
that work:
Dim
~yL'ne
As LineElement
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
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
_.)
Code Settings
~ Auto Indent
!---------_.._--)
Tab Width:
i4
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
82
I Chapter 6: Variables I
and concatenate "My Hourly Rate is" with the result of the
FormatCurrency function.
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.
End Sub
In this example, we have a
variable named BookTitle that
is declared as a String. It is
given a value of "Learning
MicroStation
VBA".
Four
different functions are then
used
with
the
variable
BookTitle as a parameter and
the result displays in four
MessageBoxes.
OKJI
Learning
83
~lic
oStation IIBA
84
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
.' oK
"j
[ Cancel)
Isidewalk
In this example we use an
InputBox to allow the user to
enter the name of a new level. We
then convert it to upper case and
use it to add a new level
(AddN ewL eve 1) to the active design
file.
-..,=-="~''''~
..
.. ,~,
Edit
ern
= - -- -- -,- -- -
chapter07.dgn
Name
j Number
[ @All Levels
- [> Fillers
,.,.!'::-~~~~
. (.:".
Default
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
Debug.Print
is used to
place text in
the
Immediate
Window. It is
often used to
display text to
aid in
debugging
our
applications.
To view the
Immediate
Window, go
to the VBA
menu View>
Immediate
Window.
85
lcase
<
lo~ers
capital letters.
StrConv
Function StrConv(String . Convers ion As VbStrConv. _
[Lo cale IO As LongJ)
Learning
~1icrostation
Vba
OK]
Each day of the week (Sunday through Saturday) has a number assigned
to it. The Weekday Name function takes that number and converts it to the
day's name.
Sub TextWork05 ()
Dim TodaysDate As Date
Dim WeekDayNumber As Long
TodaysDate = Now
WeekDayNumber = Weekday(TodaysDate)
MsgBox WeekdayName(Week DayNumber)
MsgBox WeekdayName(WeekDayNumber . True)
End Sub
86
Monday
Mon
r----'OK-' ')1
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
Sub TextWork05B ()
Dim MonthNum As Long
For MonthNum = 1 To 12
Debug.Print MonthName(MonthNum)
Next MonthNum
End Sub
I-Iay
June
July
August
September
October
November
December
87
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 ()
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.
TextWork08 ( )
Debug . Print
Debug . Print
Debug.Print
Debug.Print
End Sub
,
,
.
.
vbTextCompare)
vbTextCompare)
vbBinaryCompare)
vbBinaryCompare)
88
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.
Sub Bubb l eSort ()
Dim strNms(O To 7) As String
strNms(O)
"Jerry "
strNms(l)
"Ca ndice "
strNms(2)
"Brandon "
strNms(3)
"Kyle "
"B enjam i n"
strNms(4)
"J acob "
strNms(5)
st r Nms(6)
"Nathan "
"Ol i via "
strNms(7)
Di m MadeChange As Boolean
Di m tmp Name As St r i ng
Di m I As Long
MadeChange = True
While MadeChange = True
MadeChange = False
For I = LBound(strNms) To UBound(strNms) - 1
If StrComp(strNms(I), strNms(I + I),
vbBinaryCompare) = 1 Then
tmpName = strNms(I)
strNms(I) = strNms(I + 1)
strNms(I + 1) = tmpName
MadeChange = True
End If
Next I
Wend
For I = LBound(strNms) To UBound(strNms)
Debug . Print I & " " & strNms(I)
Next I
End Sub
The firs t thing we do is declare an array of strings and give each element
in the array a value.
Dim MadeChange As Boolean
Di m tmpName As String
Dim I As Long
MadeChange = True
Now we are setting up for the sorting portion of our routine. We want to
run through the sorting portion at least once so we set the MadeChange
variable to True and then immediately begin a While ... Wend routine.
While MadeChange = True
MadeChange = False
For I = LBound(strNms) To UBound(strNms) - 1
If StrComp(strNms(I) , strNms(] + 1 ),
vbBinaryCompare) = 1 Then
tmpName = strN ms(I)
strNms(I) = strNms(I + 1)
strNms(I + 1) = tmpName
MadeChange = Tr ue
End If
Nex t I
Wend
The last little segment of code prints out the elements in the strNms
variable array in their sorted condition.
89
90
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)
91
This
procedure
displays
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
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
InStr
Function In St r( [ StartJ, _
[S tr in g1J, [S t r in g2 J, _
[C ompar e As VbCom pa reM et hod
C:\Microstation VBA\docs\chapter07.dgn
turns into
c: //Microstation VBA//docs//chapter07. dgn
OK"n")
93
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 Tex tWork15 ()
Dim FilePath As String
Dim FirstFolderPath As String
Dim SecondBackSlash As Long
FilePath = ActiveDesignF il e.Fu l lName
SecondBackSlas h
InStr(4, FilePath, "\ " )
FirstFolderPath
Left ( Fil ePath , SecondBackSlash)
MsgBox Fi lePath & vbCr & FirstFolderPath
End Sub
94
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
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
""
Variantistring(O to 3)
XSPIrt
xSplrt(O)
"C:"
String
xS plrt(1)
"Microstation VBA"
"docs"
String
xSplrt(2)
xSplrt(3)
"chapter07.dgn"
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
EJle
!;.dit
FQ.rmat
yjew
tielp
C:\Microstation VBA\docs\chapter07.dgn
97
169
170
171
172
173 174
175 176
177
v,
.>.i
Now that you know that character 169 is the copyright symbol, you can
use it in a message box:
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
98
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
$123,456.78
$123,457
$.12
$0.1 2
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
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 ,
MsgBox For matDateTime(Date ToFormat ,
MsgBox FormatDateTime(DateToFormat,
MsgBox FormatDateTime(DateToFormat ,
MsgBox FormatDateTime( DateToFormat ,
End Sub
vbGeneralDate)
vbLongDa t e)
vbLongTime)
vb ShortDate)
vbShortTime)
100
1/1 /20054:45:00 PM
C OK
-j
K"'---OK-"-"-ll
4 :45:00 PM
r--' OK -'-
16:45
1/1/2005
_.
OK
r-
OK
..
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?
Sub Text Work 24( )
Dim My Phone As Str in g
My Phon e = "800555121 2"
MsgB ox Format(My Ph one, "(###) ###-#### " )
End Sub
(800) 555-121 2
&
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
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
"1" , _
"2", _
"3 ", _
"4", _
I Numeric Functions I
105
2
3
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
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
Function ToMile s(DistancelnFeet as Double) As Double
ToM il es = Di s t ance l nFeet / 5280
End Funct i on
The function ToN i 1es allows us to supply a distance in feet that returns
the distance in miles. Actually, the return value is in decimal miles.
Another way to divide numbers is using the backslash symbol (\ ). This
returns a whole number instead of a decimal number. 5 \ 2 = 2.
I Numeric Functions I
107
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
108
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.
Sub Tes tT anl ()
Dim XChange As Double
Dim YChange As Double
Dim Pi As Double
Dim HypAngleDegrees As Dou ble
Dim HypAngleRadians As Double
Pi = Atn(l) * 4
XChange = CDbl(InputBox("Enter X Side Length: " ))
HypAngleDegrees = CDbl ( InputBox("Enter Angle: " ) )
HypAngleRadians = HypAng l eDegrees * Pi / 180
YChange = Tan ( HypAngleRa dians) * XChange
Debug. Pri nt "Tes tTanl( ) "
I Numeric Functions I
Debug.Print
Debug.Print
Debug.Print
Debug.Print
End Sub
109
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 ()
YChange = 3
HypAngleDegLees = 36.8699
HypAngleRadians = 0.643501149881057
XChange = 3.99999965760191
A ,
>
110
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
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
36.869897645844
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
C .i
Above we use the COb1 function to convert the results of the InputBox to
a double.
Sub TestClnt ()
Deb ug . Pri nt
Debug.Pr i nt
Debug.Pr i nt
Deb ug . Pr in t
End Sub
Cl nt(4 .5 6)
Clnt(4 . 23)
Clnt( - 4 . 56)
Cl nt (- 4 . 23)
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
CLng(4OOOO.56)
CLng(4OOOO.23)
CLng(-4OOOO.56)
CLng(-4OOOO.23)
40 000
-4 0 001
-40000
V
,...;:;f.;
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
Debug . Print
Debu g .Pr int
Debug . Print
End Sub
Fix (4OOOO.56)
Fix(4OOOO . 23)
Fix( -40000.56)
Fix(-4OOOO.23)
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.
Sub Test Val ()
Debug.P r int
Debug.P r in t
Debug . Print
Debu g.Pr in t
Debug . Print
Debug. Pr int
End Sub
Va l ( "4 . 5""" )
Va 1 ( "4.5 i nches " )
Val( "$5 , OOO " )
Val( "45 degrees " )
Val( "Approx . 528 0 feet " )
Val ( "23 feet 12 inches " )
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
False
True
False
Fa l se
False
,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 Tes tRound ( )
Debug.Print Round(3.14159 . 4 )
Debug.Print Round(3.14159 . 3 )
Debug.Print Round(3.14159. 2 )
Debug.Print Round(3 . 14159. 1 )
Debug . Print Round(3.14159 . 0)
Debug . Print Round(1.455. 2 )
Debug.Print Round (1. 455 . 1 )
Debug. Print Round(1.4 . 0)
Debug . Print Round(1.5 . 0)
End Sub
3 . 142
3 . 14
3 .1
3
1. 46
1. 5
1
2
5 Mod 2
7 Mod 3
23 Mod 7
280 Mod 2
. >.
I Numeric Functions I
115
-1
0
1
116
=?
(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.
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
117
118
r '-Ab~it" ll [
B.etry
II
Ignore
I MessageBoxes I
11 9
If you change a file name extension, the file may become unusable.
Are you sure you want to change it?
120
C OK
. ,.
~
It3
Mi~roStation.
""
".
J[
Cancel
r. y~~ ] I
No
End Sub
~<''''''''
~'?>rnN"""'>:'--'~)~~"'<""""
'''- ,
;rjtle ~9~~H~r~:.: ~
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
OK
[ Cancel
The InputBox has additional parameters we can use. We will discuss four
of them here.
Sub Te s tlnputBo x2()
Dim InpRet As String
InpRet = InputBox( "Enter Level Name :" , _
"Level Creator " , "Str i ping " , D, 0)
Debug.Print "User entered" & InpRet
End Sub
OK
.1
Cancel )
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
The Now function gives the current system date and time. This is useful
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:
Sub Test DateAdd ()
Di m NowDate As Date
NowDate = Now
Debug.Print NowDate
Debug.Print NowDate
Debug . Print NowDate
Debug . Print NowDate
Debug.Pr i nt NowDate
Debug.Print NowDate
Debug .P rint NowDate
Debug . Print NowDate
End Sub
5/28/2005
5/28/2005
5/28/2005
5/28/2005
5/28/2005
5/28/2005
5/28/2005
5/28/2005
11: 40:54
11:40:54
11:40:54
11:40:54
11:40:54
11: 40:54
AN
AM
AJI'!
AJI'!
AM
AM
6/1/2005 11:40:54 AM
5/28/2005 3:40:54 PN
5/28/2005 11:44:54 AN
5/28/2005 11: 40:58 AM
9/28/2005 11: 40:54 ,A.Jv!
6/1/2005 11:40:54 AJI'!
5/28/2009 11:40:54AJ1'!
8/28/2005 11:40:54 AM
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
Hour-s
8718445
Minutes 5 2 3106644
seconds 31386398632
Months
11936
weeks
51895
Year-s
995
Quar-te r- s
3979
<
>,-
124
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!}''
.'"
.'. ~
C6K-..~
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
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
C:\Program
C:\Program
C:\Program
C:\Program
C:\Program
Files\Bentley\.
Files\Bentley\ ..
Files\Bentley\Documentation
Files\Bentley\Licensing
Files\Bentley\MicroStation
C:\P r og ram
C: \P r og r am
C: \Program
C: \P r ogram
C: \ Pr ogram
Fi les\ Be nt l e y \ Mi c r o St at i o n\ a t l 71.dll
Fil es\ Be ntle y \ Mi cro Stat i o n\auto mationdgn . d l l
Fi l es\ Bentl ey\ Mic r oStat i on\bdti d oc .htm
Fi l es\ Bent l ey \ Mi c r oStation\ be nt le y .mi c r ostati on.host i ng.dl l
Fi les\Bent l ey\Mic r ostat i on\ be nt l ey . mi c r ostat i on.textlib . d ll
~I
v .
>1
III
127
IlnputBox I
DgnFiles(3)
DgnFiles(4)
DgnFiles(5)
"C:llvlicroStation
"C:llvlicroStation
"C:llvlicroStation
"C:'lvlicroStation
"C:llvlicroStation
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
128
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
E.i1e
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
"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.
Sub TestDe l eteSettingl ()
DeleteSetting "L earn i ng Mic roStat i on VBA " , _
"Chapter 9", "SaveSetting "
End Su b
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.
Sub TestGetSetti ngs ()
Di m AllSetti ngs As Variant
AllSett i ngs = GetAllSett in gs( "L earn in g Mi croStation VBA " , _
"Chapter 9 " )
End Sub
130
"Save Setting"
"ttWorks"
"SaveSetting2"
"ttWorks2"
"SaveSetting3"
"ttWorks3"
ASCII FILES
131
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
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
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.
Be careful if you use FreeFi 1e for multiple variables as we have done
here. If you assign FFileA and FFileB file numbers with FreeFi 1e one
right after another, they will both hold the same value. FreeFi 1e returns
a different number only after a file has been opened. So, use Free Fi 1e,
open the file it was used for, then use it again to open the next file. This
keeps us from getting the same number and accidentally reading from
or writing to the same file when we meant to read/write to two separate
files.
Here is a more advanced application of writing to ASCII Text Files. An
XML document is an ASCII text document with specific formatting.
Our next example creates a Microsoft Excel XML document that
contains all of the EXE files in the 1C:\Windows\System32" folder, as
''len as the date and time the file was last modified. After the XML file is
written, you can open it in Microsoft Excel.
133
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"" >"
Print #FFileA. " <Worksheet ss:Name= "" EXE Files"">"
Print #FFileA. " <Table>"
exeFile = Dir("C:\Windows\System32\*.exe")
While exeFile <> ""
Print HFFileA. "
<Row> "
Print #FFileA. _
<Cell><Oata ss:Type= "" String""> " & exeF i le &
"</Data><ICe l l >"
Print #FFileA. _
<Cell><Oata ss :Type=""String"">" &
FileOateTime( "C:\Windows\System32\ " & exeFile) &
"</Data><ICell >"
Print #FFi l eA. "
</Row>"
exeFile = Dir
We nd
Print #FFileA." </Table> "
Print #FFileA. " </Worksheet> "
Print #FFileA. "</Workbook> "
Close FFileA
End Sub
I Q l23Q
~ jll,~ ~ j ~ ~
A1
A
~
c.alsexi3.
E.~~!iT1!l P ex e
r.R~ ~~~~:f~~!;:
~ crdaemon exe
1~
~ r:1
313112003 60000 AM
- jI311Qo~- 6 oQ~'~ci .A~v1
;~~~~~; ~.~~.~~ ~~
3131120036:0000 AM
~ ",,~,c'~'i '~ EXE Files /."_~=c"c,.,_,.,."c~.,-,,-c __ ,,.
Ready
134
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.
Sub Rea dA SCIIB ()
Di m FF il e As Long
Di m Tex t Li ne As St r ing
Dim TextPoint As Point3d
Dim XSpl it As Var i ant
Di m Text Elem As Te xt Element
Dim Rot Ma t As Matr i x3d
FFile = Free Fi le
Open "C: \MicroStation VBA\TextPoints.txt " For Input As #FFile
While EOF(FFile) = False
Line Input #FFile , TextLine
XSplit = Split(TextLine, " ," )
135
TextPo i nt.X
TextPoin t .Y
TextPoint.Z
Set TextElem
XSp l it(O)
XSplit(l )
XSplit(2)
= App l ication.CreateTextElementl(Nothing, _
XSplit(3), TextPoint, RoHlat)
ActiveModelReference .AddElement TextEle~
Wend
Close /fF Fi le
End Sub
Note 2
Note 4
Note 1
Note 3
136
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
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.
Sub ForNe xtD ( )
Dir.1 X As Doub l e
Dim Y As Doub le
Di m In s Pt As Po int 3d
Di m Ce l lE l em As Cel lEl ement
For X = 0 To 10 Step 0 . 25
For Y = 0 To 10 Step 0 . 25
InsPt.X = X
InsPt.Y = Y
Set CellElem = App l i cat i on.CreateCellE l ement3( "Column ", _
InsPt, True)
ActiveModelReference.AddElement CellElem
Next Y
Next X
End Sub
' O'@C
88' O
. . . .... . . ': C
OOOGCD
i ' , . , . , ', 'C:DC
',
CDOOO
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
When we open a file to read it, we may find 1 line, 10 lines, 100 lines, or
any other number of lines to read in the file. So we keep looking at the
EOF (End of File) condition of the file. While we have not reached the
End Of File, we execute the code between the While and Wend lines.
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
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
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.
141
NewLevelC 3
NewLe vel C 2
NewLevelC 1
v
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
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
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.
143
In this example, look at the fi rst character of the level name entered.
There are multiple possible blocks of code we may want to execute based
on the first character. If the first character is not A, B, C, D, or E, display
a MessageBox and do not add a new level. If the first character does
meet our criteria, prep end characters to the entered level name as you
add the level name.
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
!;.nd
tleip
'-oK-O.Oll
When handling errors, you can display MessageBoxes to let the user
know an error occurred, or you can handle the specific error so the user
does not know anything happened.
Now, let's take another look at the code in detail. The first thing to do in
the procedure is state:
On Error GoTo errhnd
This tells VBA that if an error is encountered jump to the area of code
labeled "errhnd". Here it is:
errhnd :
Select Case Err . Number
Case 13 ' Type Mi smatch
MsgBox "Line Lengths must be numeric ."
Err . Clear
End Select
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?
End
Debug
: )1 [
Help
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.
Sub Te s tEr r orHndB ()
On Error GoTo errhnd
Dim LineLength As Dou ble
LineLength = CDbl (InputBox( " Enter Line Length :" ))
Exit Sub
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
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
147
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
GetOb j eet assumes the object we are getting has already been created by
148
"On Error Goto 0" (that's a zero after Goto) tells VBA to ignore the
previous "On Error" statements and continue as if there is no error
handling. This comes in handy because you will see an error dialog box
showing the error number and description plus a Debug button.
Clicking Debug takes you to the line of code that has the problem. Once
you find and fix the bug, you can comment out the "On Er ror Goto 0"
line so your Error Handling code is at work again.
We covered a number,
not
a
although
comprehensive list, of
useful and commonly
used VBA calls. You can
use the Object Browser
in VBA to display all
VBA
calls
natively
available to us. We will
Object
discuss
the
Browser later in this
book. Here is a snapshot
of what you will see if
you filter on the VBA
Reference, the DateTime
Class, and the DateD i ff
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)
Part
Description
interval
date 1 , date2
firstda vofwe ek
Optio nal. A constant that specifies the first day of the week. If
not specified, Sunday is assumed .
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:
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
10
Visual Interface
It is time to begin working with the
-- Insertion Point
1 X 10
lz
Cells
]0
\0
--.-------------.--..--... --.-;
\ Column
Cancel
151
152
Conlrols
,~- A
I
abl ~ [ffij
17r.;=!O-,
Ce"iLlnsertion ,
Level
Cells
.~.
\:
.. "
I SIDEWALK
I Column
" l'8J
3
3
Insertion Point
jJ~~_~__~J
Insert
Cancel
..!..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.
CommandButton 1
False
: 0
&H8000000F&
153
-.:J
1 - fmBackStyleOpaque
False
CommandButton 1
v:
True
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
@, i.II.E'tlt.J~.
@i' TextAlign
M;...,;;;;;;;;;...._ _ _......._ _ _ _ _ _ _ _ _ @ , TextLength
E nd Su b
< i
@i' Top
@, Value
@i' Vi sible
@'Width
154
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
155
When you select an event not previously selected, VBA fills m the
framework of the event for us.
. _. ___._._. .
._
_._ .
...:J
End Sub
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.
Sub
CommandButtonl_~l ouseDown
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.
156
"Enter Level
Name:"
= t x t XVa l ue .Te x t
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.
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 singleline 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
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
Label
Labels help users know what to enter or select. Properties of note are as
follows:
abl
Captio n
Font
TextBox
The TextBox allows users to enter text or display text, often in singleline mode so text is displayed in one line. You can stretch a TextBox
vertically to display multiple lines.
159
Properties
Text
Locked
MaxLength
Multiline and
WordWrap
PasswordChar
160
~ (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
Text
Style
Listlndex
ListCount
ColumnCount
I ListBox I
161
Methods
Addltem
Removeltem
Clear
Events
Cli ck
Change
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
Text
Mu ltiSelect
Se lected
Co lumnCount
Methods
Add ltem
Same as ComboBox
Removeltem
Clear
Same as ComboBox
162
Events
Click
Same as ComboBox
Change
Same as ComboBox
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
Caption
TrippleState
Value
Events
r.
Click
Change
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
Caption
Group Name
If
If
If
lf
If
Events
Click
Change
DblClick
~ 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
Caption
TrippleState
See CheckBox.
Value
See CheckBox.
Events
Click
Change
DblClick
164
XV"
[J
FRAME
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
Caption
Visible
True or False.
.-J COMMANOBuTTON
Use CommandButtons to give users something to click on, such as these
(commonly captioned): "OK", "Cancel", "Print", "Open", and "Close".
Properties
Captio n
TakeFocusOnClick
Events
Click
I MultiPage I
165
Properties
MultiRow
Selected Item
Style
TabOrientation
Methods
Tabs.Add
Events
Change
..: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
Value
Pages.Count
MultiRow
See TabStrip.
Methods
Pages.Add
166
Events
Change
.:!:I
SCROLLBAR
Scroll Bars allow the user to select and change numeric values. The
rectangle that moves as the value changes is called the Thumb.
Properties
LargeChange
Sma liChange
Min
The Minimum Va lue the Scroll Bar can have when the
Scro ll Bar is Horizontal.
Max
Value
Events
Change
Scroll
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
Delay
Min
Max
Small Change
Value
Events
GZJ
Change
Spin Up
SpinDown
IMAGE
Use the image control to display images in your interface. Acceptable file
formats are .bmp, .gif, .jpg, .wmf, and .ico.
Properties
BorderStyle
0= None, 1 = Single.
Picture
PictureSizeMode
PictureTiling
168
,.",~
--------=~:;
1-1
- Insertion Point
: r-1:----- ~I
..,
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".
Placing controls in the form is only the beginning. The Levels
ComboBox needs to be filled with all of the levels in the active drawing
and the Cells ComboBox needs to be filled with all of the cells available.
Fill these ComboBoxes before the user sees the form. To accomplish
this, go to the Initialize Event of the User form .
Right-click on the form and select View Code in the pop-up menu. By
default we are taken to the Click event of the form. Select In i t i ali zein
the Procedure ComboBox.
Pr i vate
Dim
Dim
Dim
For
Sub UserForm_InitializeC)
MyLevel As Leve l
MyCellEnum As CellInformationEnumerator
MyCell As Cell Information
Each MyLevel In ActiveDesignFile.Levels
cmbLevels.AddItem MyLevel.Name
Next
Set MyCellEnum = _
Application . GetCellInformationEnumeratorCTrue. True)
169
Here is the code in the Initialize Event of the UserForm. It should look
like this:
Private
Di m
Dim
Di m
Fo r
Next
Se t MyCellEnum = Appl ication . GetCellInfo rmationEnumerat o r (True,
Whi l e MyCel l En um . Move Ne xt
Set My Ce 11 = MyC e llEnum .C urrent
cm bCel l s . Add I tem MyCe ll.Na rne
Wend
End Sub
Tr ue)
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
We need to put the same code into the KeyPress events of the txty and
txtZ controls. Simply copy and paste the code. One little change is all it
takes. When looking for a period, use the control name. After copying
and pasting the Select Case code, change the name of the control in the
InStr function to match the control of the KeyPress event.
Private Sub txtX_KeyPress(ByVal _
KeyAscii As MSForms.ReturnInteger)
Select Case KeyAscii
Case Asc( "O" ) To Asc( "9 " )
Case Asc ( "." )
If InStr(l. txtX . Text . "." ) > 0 Then
171
0
Let's handle the Cancel button next. When the user clicks the Cancel
button, we want to close the form. We have been right-clicking on
controls and selecting View Code to get into the events of the controls.
Double-click on the Cancel button now. This is another way to get into
the form's code area.
Private Sub cmdCancel CllCk()
Unload Me
End Sub
172
Before inserting, make sure the user selected a level and a cell to insert.
Use the txtX, txtY, and txtZ text boxes to get X, Y, Z values for the cell
origin. After creating the cell element, set its layer to the value of the
cmbLevels ComboBox Text property. The last thing to do is add the
element to the active model.
We have only one button left, the "PICK" button used for selecting the
cell origin. What do we want it to do? The button should be used to
allow the user to select a point in MicroStation instead of entering the X,
Y, and Z values by hand. To make the program work even better, if the
user has already selected the level and cell, we will insert the cell at the
selected point automatically. This keeps the user from needing to click
th
___ e "T_nser t"
_ h_u tt on aft er Cl'1Ck'mg th e "Plr'K"
\., _ h. ut ton.
173
nn
174
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
175
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.
2
2
3
3,5
4
5
3
3
3
3
3
Remove Selected
0
0
0
0
0
0
0
Plot Points
1
2
3
4
5
6
7
Cancel
176
PointSplit(l)
POintSplit(2)
PointSplit(3)
End If
Wend
End Sub
When the user clicks the Read button, we open the file specified in the
TextBox "txtPointFile" for input (this means we are going to read the
file), Since we have not reached the End Of File, we read the next line
from the file, split it into its elements, and add the elements to the
ListBox. Notice how we use "Addltem" to add the X component of the
point. AddItem is only used to add items to the first column of the
ListBox. Each additional column's value is set by using the List property.
When using 'List: specify the line index and the column, then give it the
value you want to put into the column.
The Remove button is meant to remove any items selected in the
ListBox. Since multiple items can be selected at once, be careful as you
remove the items.
Priv a te Sub btnRemove_Cl i ck()
Di m I As Long
For I = lst Point s. Li stCo unt To 1 St ep - 1
If ls t Poi nt s . Se l ected(I - 1 ) Then
lstPoints.RemoveItem I - 1
End If
Next I
End Sub
By beginning at the last item in the list and working to the first, you
avoid potential problems as you remove selected items.
Private
Dim
Dim
Dim
Dim
Dim
For
Sub btnPlotPoints_Click()
TextIns As Point3d
TextVal As String
I As Long
PT As TextElement
RotMat As Matrix3d
I = 1 To lstPoints.ListCount
TextIns . X lstPoints . ListCI
TextIns.Y = lstPo i nts .List (I
1 . 0)
1. 1)
177
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:
Private Sub btnCancel_Click()
Unload frmPointList
End Sub
That's it for the buttons in the form. Now, how do we display the form in
the first place? In a code module, we place the following code:
Sub DoPointListReade r()
frmPointList . Sho w
End Sub
The macro DoPo i ntL i stReader is now used to display the form and all of
the great functionality we have just put in.
r
O
"
i
!
Items To Write
rv Levels
-------"-000"]
r. :~~siij~:~:tl
[
""C_~~~~__"""_" __ """"_
OK
Author
i P' Subject
1L_.
P'Title
_ _ _ _ _ _ _l
Cancel
178
Use an I f and E1s elf statement to handle the two file formats for today.
Another E1s e If statement is all it takes to add another file fo rmat
tomorrow.
Sub PrintLin e ( Lineln As String, FileNum As Long)
If optASC I I. Val ue = True Then
Print #FileNum, LineIn
179
Use the procedure Pri ntL i ne for each of the selected items found. Use
another I f and E1s elf statement for the file formats.
Sub PrintFooter(F il eNum As Long)
If optHT ML. Value = Tr ue Then
Print #F i leNum. "(/table) " & vbCrL f
End If
End Sub
180
181
182
Views
Zoom
OUT
11
O!J
IPan I
...iI
...tJ
Views
11
Zoom
Pan
~
IN
...J
...iI
.::l
...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.
r:
~:
.... .
~:.
~ ::..
. .. . . .. .
~ove...
..
: ::::: :. ::::::
: ::;:: : :::: : .. ..
..... . .. .
.....
..
.. .....
. ........ .
183
cmbViews.Listlndex = 0
ViewCen = Act i veDes i gnF i le.V i ews(l) . Center
Vi ewCen.X
scrX.Va l ue
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:
Sub SetZoo m(Zoo mValue As Long. OldZoomValue As Long)
ActiveDesignFile.Views(cmbV i ews . Tex t ) . Zoom 1 + _
(ZoomValue - OldZoomValue) / 100
Act i veDesignFile.Views(cmbViews.Text).Redraw
En d Sub
Sub SetPan (XP an As Long . YPan As Lo ng)
Dim ViewOrigin As Point3d
ViewOrigin.X
XPan
ViewOrigin . Y = YPan
ViewOrigin.Z = 0
Act i veDesignFile . Views(cmbViews.Text).Center
ActiveDesignFile.Views(cmbViews .T ext) . Redraw
End Sub
ViewO r igin
184
The Change and Scroll events for the scroll bar named scrZoom is
shown above. The code inside these events is the same. The Tag
property (as discussed previously) is there for whatever use we have for
it. Here is one way: use the tag to store the previous value. After we call
SetZoom, we set the tag value.
Now, let's talk about panning. We are using two scroll bars to set the X
and Y elements of the view's center.
Pr i vate Sub scrX_Change()
SetPan scrX .V al ue . scrY . Value
End Sub
Private Sub scrX_Scroll()
Set Pan scrX.Value. scrY.Value
End Sub
Private Sub scrY_Change()
Set Pan scrX.Value . scrY.Value
End Sub
Private Sub scrY_Scroll()
SetPan scrX . Value. scrY . Value
End Sub
I Review I
185
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
11
In th is chapter:
[B
[B
[B
[B
Adding Watches
[B
187
188
...s
i!lJndow
tlelp
One of the best tools to work with Object Models is the Object Browser.
Click on the Object Browser toolbar button to display the Object
Browser. The Object Browser can also be displayed by using the VBA
menu Vi ew > Object Browser or by pressing the <F2> key on the
keyboard.
Classes
<globals >
~ AccuD rawHints
~ ACS Manager
Q
,hI! @i'
~!
'-
~ Gt!!jllliiMi~!i!_
ACSManager
@i' AcliveSetting s
@i' AcliveWorkspace
,,~ AddAttachme ntEventsHandler
~ Arc Element
~ AreaPattern
~ Attac hment
~ Attachments
~ Auxilia ryC oordinateSystemE lement
~ 8spline
~ 8spiineCurve
"'~ AddSaveAsEventsHandl er
.~~ AddViewUpdateEvents Handler
~ 8spiineCurveElement
~ 8sp ii neSurface
~ 8spiineSurfa ceE lement
~ Cad lnputM essage
li.'tiJ Cadln putQueue
~ APP li cationBelT1f1(
~i
Class AI)plicalion
Member of MieroStatiollDGtl
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
"Members of 'Application'"
show up in the Members
ListBox.
The
Members
ListBox
displays
the
Properties, Methods, and
Events of the selected Class.
AI
OpenOesignF ile
@I PaU1
:,=.% Pi
v ;
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
v-I
~"' i
I~.I It\
Iitll .~
f-R
text
.- .. Search Resu lts - ..... -.-.... ..... :. Jh
Hi~
(de-=s-ea-:rch-:R-es-:ultc-ls ..- .......--..... -.-........_-........... _.-.-..
Library
, Class
Ii
, Member
A,
1\
'lCj~I!lII@!
J. . . .
..,~ ,
i
1\ MicroStationOGN ~ Appli cationElement
~. AsTextElement .='=') I
1\ Mi croStati onOGN @! ArcEl em ent
@i' AsTextElement
I
1\ Mi croStationOGN !el1l.uxiliarICoordinateSvstemEIE~ AsTextElement :"-: "
Members of 'Text Node Element'
Classes
@! TagOefinition
\i!a TagOefinitions
" ,~
..,~
@! TagElernent
AddTag
lI.ddTags
\i!a TagSet
~, ."~[A(j(jTeXiLine
~ TagSets
Y:i
..........J
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
~:~B~[~~~a=:~~~it~~~~~~n
End Sub
jl
@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
I.I.
n.
~~:AddNewLevel
.~~
AllachColorTable
@i' Author
@i' Client
.,,~ Close
@i' Comments
@' Company
The ''Auto List Members" list allows us to 'drill down' through an Object
Model.
191
~~.--~~- ~?'r-;-:~
"'~<-~-,...~"'-..;,.'" ~>
''''_''fi;;:;<p
r'
~Tq
h fl
-"
-~,""""'f'''' "~~',;:
~~->
,.
~t~
OJ
r-
"< ""'~
-----,.
&1 MicrC!SIi!tiop VB V}sual Basic for AppiicaticlV5 Help.,;.,., .,,,,,~\;,~;,,,, ...":.,:'",< ;:{~.'~h"""" :"'o>~2{,","""~ ,;,' ~l1~
~1Il
c:i>
<?
~~.
IApplication Strueture
Application Object
~..
r-
"
ApplicationElement Object
..... :,
App!icationlO Property
ApplicationObiectConnector Obje
r--
A ppl~ H o ri20nlaIScalingF i, F o rE M f
t--
ApplyRotation Property
ApplyS aveaViewE!ement Methoc
t--
Appro:'limateWitMrcs Method
ArcE lement Object
Area Melhod
AreaModeHofe Property
AreaPaUem Object
AreaPatternDelta Property
ArePolesCollinear !vi elhod
ArrowSymbolCeliName Propert!,'
Allow TerminatorChalSymbol PIO~
Arrow TelminatorFont Ploperty
Allow TerminatorSymbolT ype Pial
As.AppficationElement Propelty
As.AlcElement PlOperty
AsAttachment Properly
Appl ica t i on
AsAu~ilialyCoOidinateSystemElell
AsBsplineCurveElement Properl!,'
AsBsplineSurfaceElement Proper
AsCeUElement Properl!,'
AsChainableElement Property
AsClosedE lement PlOperl!,'
AsComplexE lemenl Propelly
AsComplexShapeElemenl Ploper
AsComplexStringE!ement Properl!
AsConeE lement Ploperl!,'
AsCul veElement Ploperly
AsD imensionElement Property
AsOroppableElement Propelty
AsE liipseE lement Properly
AsE liiplicalE lemenl Property
AslntersectableElement Property
AsLineE lement Properly
AsMulliLineElement Property
Qi spla~
t--
r-t--
Corrmar.,j 5tate
t--
(ComrnandSt a te)
{Boo l)
t--
t--
He ight {LonQ )
t--
t--
t--
t--
I s Ser i (] I i
r--
Il ey inArguments {String)
Z6<j
,,'
S.:
{8 00 I }
t--
,<
Na ma {String}
-_._-'-
'-
) ,
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
Ed~ion"
DesignFileiOesignFile
ModelReferenceiModelRef, I
Settings,Settings
WorkspaceNVorkspace
CeliLibrary
;;
8spline,Bspline
I'
CadlnputQueue/CadlnputQ' I'
string
I:
CommandStatelCommandS
Long
I;
CursorlnformationlCursorlr \'
ObjectNBProject
string
800lean
800lean
Long
I:.
CurreniGraphicGroup
HasActiveDesignFile
HasActiveModelReference
Height
IsAcademicVersion
IsCeliLibraryAttached
IsRegistered
Is Serialized
KeyinArgumenis
LeftPo s~ion
-4
MdlLib
MessageCenier
Name
Path
ProcesslD
RasterManager
standardsCheckerConirolier
"ustation"
"C:'Program FileslBeniley'MicroStation"
3160
TopPos~ion
User Name
V8E
Version
Visible
W eith
Boolean
800lean
800lean
800lean
string
Long
MdlLibrarylMdlLibrary
MessageCenieriMessageC
string
r.
string
I:
Long
RasterManager lRasterMan I
standard sCheckerConirolh I
Long
I.
string
ObjectN BE
string
800lean
Long
I;'
1\
-4
"Administrator"
"Version 08 .09 .00.92 W ndows x86"
True
1608
193
Application Object
The Application Object points to the MicroStation Application.
Accessors
Sub TestApplicationA ()
Dim MyApp As New Application
MsgBox MyApp . Path
End Sub
Sub TestA pplicationB ()
Dim MyApp As Appl i cat i on
Set MyApp = Applicat i on
MsgBox MyApp . Path
En d Sub
Both examples shown here result in the variable MyApp pointing to the
MicroStation Application Object. Once a variable is pointing to the
Application, we can use that variable to manipulate the Application
Object through its Properties and Methods.
The Application Object is always available through the exposed Object
named "Application". This means when we are in VBA, we can use the
Object named Application at any time.
In addition to accessing the Application's properties and methods,
additional objects and collections under the Application object can be
accessed by traversing the object model. Do this by typing "Application",
the period key, and then the next level of the Object Model.
Sub TestApp l icationC ()
MsgBox Appl ic at i on.Pat h
End Sub
In this example, we have not declared any variables or set any variables.
We just use the Object named "Application" because it is always exposed
to us.
A comprehensive list of objects in the MicroStation Object Model is
available on the CD that accompanies this book. It is not feasible to give
the entire Object Model here in print but you will get an understanding
as to how large the Object Model is. Let's take a look at a selection of the
Properties and Methods of a few of the Objects we deal with on a regular
194
Application
~ Property ACSManager As ACSManager (read-only)
~ Property Active Des i gnF i l e As Design File (readonl y )
~ Property ActiveModelRefe r ence As
Mode l Refere nce {read-on l y}
~ Property ActiveSettings As Set t ing s {r eadonl y }
~ Property Act i veWorkspace As Workspace {readon 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
~
~
~
~
~
~
~
~
~
~
~
195
196
197
198
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
199
200
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
201
202
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
~
~
~
~
~
~
~
~
~
~
203
204
~
~
~
~
~
~
~
~
~
o
o
o
o
o
~
o
o
o
o
o
o
o
o
o
205
206
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
207
208
[8
[8
[8
[8
[8
[8
[8
[8
[8
[8
[8
[8
[8
[8
~
~
~
~
~
~
~
209
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
~
~
~
~
~
~
~
~
~
~
~
~
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
211
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
Function Point3dSubtract(Pointl As Point3d,
Point2 As Point3d) As Point3d
Functi on Point3dSubtractPoint3dVector3d(Base
As Point3d, Vector As Vector3d) As Point3d
Function Point3dTripleProduct(Vectorl As
Point3d, Vector2 As Point3d, Vector3 As
Point3d) As Doub l e
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
Fun ction Point 3dZero() As Point 3d
Funct i on PointsToPixelsX(PointCoordinate As
Double) As Long
Function PointsToPixelsY(PointCoordinate As
Double) As Long
Property ProcessID As Long
{read-only}
Sub Quit()
Function Radians(Degrees As Double) As Double
Function Range3dContainsPoint3d(Range As
Range3d, Point As Point3d) As Boolean
Function Range3dContainsXYZ(Range As Range3d,
X As Doub l e, Y As Double, Z As Double) As
Boolean
Funct i on Range3dEqua l (Rangel As Range3d,
Range2 As Range3d) As Boolean
Function Range3dE qua l To l erance(RangeO As
Range3d, Rangel As Range3d , Tolerance As
Doub l e) As Boolean
Funct i on Range3 dEx t entSq uare d(Range As
Range3d) As Double
Functio n Range3dFromPoint3d(Point As Point3d)
As Range3d
Funct i on Range3dFromPoint3d Point3d(PointO As
Point3d , Po i ntl As Point3d) As Range3d
Funct i on
Range3dFromPoint3dPoint3dPoint3d(PointO As
212
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
213
214
[B
[B
[B
[B
~
[B
[B
[B
[B
[B
[B
[B
~
~
[B
~
~
~
~
~
~
~
~
~
~
~
215
216
~
~
~
~
~
~
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
217
[B Function
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
218
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
219
220
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
Vector3dFromMatrix3d TimesVector3d(Matrix As
Matrix3d, Vector As Vector3d) As Vector3d
Function Vector3dFromMatrix3dTimesXYZ(Matrix
As Matrix3d, X As Double, Y As Double, Z As
Doubl e) As Vector3d
Fun ction
Vector 3dFromMat r i x3d Tran spos eT i mes Ve ctor 3d(Ma t
ri x As Matr i x3 d , Vector As Vecto r 3d) As
Vector3d
Function
Vector3dFromMatrix3dTransposeTimesXYZ(Matrix
As Matrix3d, X As Double, Y As Double, Z As
Double) As Vector3d
Function Vector3dFromPoint3d(Point As Point3d)
As Vector3d
Function
Vector3dFromTran s form3dCo1umn(Transform As
Transform3d, Col As Lo ng) As Vector3d
Function Vector3dFromTransform 3d Row(Tran sfo rm
As Trans fo rm3d, Row As Long) As Vec tor3d
Function
Vector3dFromTransform3dTimesVector3d (T ransform
As Transform3d, Vector As Vector3d) As Ve cto r3d
Function
Vector3dFromTransform3dTimesXY Z( Transform As
Transform3d, X As Double, Y As Double , Z As
Double) As Vector3d
Function
Vector3dFromTransform3dTrans1ation(Transform
As Transform3d) As Vector3d
Function
Vector3dFromTransform3dTransposeTimesVector3d(
Transform As Transform3d, Vector As Vector3d)
As Vector3d
Function
Vector3dFromTransform3dTransposeTimesXYZ(Trans
form As Transform3d, X As Double, Y As Double,
Z As Double) As Vector3d
Function Vector3dFromXY(Ax As Double, Ay As
Double) As Vector3d
~
~
~
~
~
~
~
~
~
221
222
~
~
~
~
~
~
~
~
~
~
~
ApplicationObjectConnector
~
Attachment
~
Sub Act iv at e ()
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
223
224
[B
[B
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
225
226
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
227
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 {readonly}
~ 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
[B
[B
[B
[B
[B
[B
[B
[B
[B
msdCadlnputTypeAnyJ. [Type2 As
MsdCadlnputTypeJ. [Type3 As MsdCadlnputTypeJ.
[Type4 As MsdCadlnputTypeJ) As CadlnputMessage
Sub Se ndCommand (Co mm an d As St ri ng .
[ Tr eatLikeKeyboardlnput As Bo olean J)
Sub SendDataPoint(Da t aPoint As Point 3d.
[Vi ewSpec i f i er As Varia nt J . [Q ualifi er As
LongJ)
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)
Sub SendDragPoin t s(DownPoint As Po i nt 3d .
UpPoint As Point3d. [ViewSpecifier As VariantJ.
[Qual ifie r As LongJ)
Sub SendKey in(Keyin As String)
Sub SendLast lnput()
Sub Sen dM essage To Appl i cationCMd l App li cation As
Str in g. Message As String)
Sub SendResetC)
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}
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
229
230
~
~
~
~
~
~
~
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 (readonly)
~ Property AsAuxiliaryCoordinateSystemElement As
AuxiliaryCoordinateSystemElement (read-only)
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
231
232
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
233
234
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
235
236
~
~
~
~
~
~
~
~
~
ElementEnumerator
~ Function BuildArrayFromContent s () As Ele me nt ( )
~ Fun ct i on Cl one() As El ement Enu me r ato r
~ Property Current As El ement {read-on l y}
~ Function M
oveNext() As Boolea n
~ Sub Reset()
ElementScanCriteria
~ Sub Excl udeAll Cl asses()
~ Sub Exc lu deAllColors()
~ Sub Exc l ud eA ll Leve l s()
~ Sub Ex c 1 ude Al l Li ne Sty 1e s ( )
ei ghts ()
~ Su b Excl udeA 11 Li neW
~ Sub Exc lu deA l lSubtypes()
~ Sub Exc l udeA 11 Types ( )
~ Sub Exc l udeGraphica l ()
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
237
level
~
238
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
ModelReference
~ Sub Activate()
~ Sub AddElement(Element As Element)
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
239
240
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
Function GetSheetDefinition() As
SheetDefinition
Function GetUserAttributeData(AttributeID As
Long) As DataBlock()
Function GetXData(ApplicationName As String)
As XDatum()
Fun cti on GetXDa t aA ppl ication Names() As
String ( )()
Property GlobalOrigin As Point3d (read-only)
Property Graphi cal El ementCa che As El em ent Cach e
{read-only}
Function HasAnyXData() As Boolean
Function HasXData(ApplicationName As String)
As Boolean
Property 1s3D As Boolean {read-only}
Property 1sActive As Boolean (read-only)
Property IsAttachment As Boolean {read-only}
Property 1sElementSelected As Boolean {readonly}
Property IsLocked As Boolean
Property 1sReadOnly As Boolean (read-only )
Property Levels As Levels {read-only}
Property MasterUnit As MeasurementUnit
Funct io n MdlModelRefP() As Long
Prop e rt y Name As String
Property ParentModelReference As
ModelReference
{read-only}
Sub PropagateAnnotationScale()
Function Range(IncludeAttachments As Boolean)
As Range3d
Sub RemoveElement(Element As Element)
Sub ReplaceElement(OldElement As Element,
NewElement As El ement)
Function Scan([ScanCriteria As
ElementScanCriteria]) As ElementEnu merator
Sub SelectElement(Eleme nt As Element,
[DisplayAsSelected As Boolean = True])
I Review I
~
~
~
~
~
~
~
~
~
~
~
~
241
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
12
MSDDESIGNFILEFoRMAT
msdDesign FileFormatCurrent
msdDesignFileFormatDWG = 3
msdDesignFileFormatDXF = 4
msdDesignFileFormatUnknown
msdDesignFileFormatV7
1
msdDesignFileFormatV8
2
-1
243
244
The other way is to use the member name without the enumerator
name:
ActiveDesignFile.SaveAs "t est.dgn ", True, msdDesignFileFormatDWG
245
0
1
2
3
4
5
6
7
MsdAngleFormat
msdFormatDD_DDDD = 0
msdFormatDD MM SS = 1
msdFormatGradians = 2
msdFormatRadians = 3
246
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
247
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
10
msdChangeTrackActionModelDelete
msdChangeTrackActionModify = 3
msdChangeTrackActionModifyFence = 5
msdChangeTrackActionNewF il ePositionAndMod ify
248
481
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
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
-1
MsdDevelopableElementOutputType
msdDeve1opab1eCones = 4
msdDeve1opab1eConesP1anar = 5
msdDeve1opab1eRu 1eLines = 0
msdDeve1opab1eRu 1eLine s P1anar
1
msdDeve1opab1eShapes = 2
msdDeve1opab1eShap esPlanar
3
Msd Dialog BoxResult
msdD i alogBoxResu1tApply = 1
msdD i a1ogBoxResu1tCance1 = 4
msdD i a1ogBoxResu1tDefau 1t = 5
msdO i alogBoxResu 1tHe l p
10
msdD i a1ogBoxResu l tNo = 7
msdOia1ogBoxResultOK = 3
msdDialogBoxResu1tReset = 2
msdDia1ogBoxResultRetry = 8
msdDia1ogBoxResu1tStop = 9
msdDia1ogBoxResu1tYes = 6
msdDi a 1ogBoxResu1 tYesToA 11
11
MsdDimAccuracy
msdDimAccuracyO = 0
msdDimAccuracy1 = 129
msdDimAccuracy16th = 8
msdDimAccuracy2 = 130
msdDimAccuracy3 = 132
msdDimAccuracy32nd = 16
msdDimAccuracy4 = 136
msdDimAccuracy4th = 2
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
Msd Oi mAng leMeasure
MsdDimAngleMeasureAngle = 1
MsdDimAngleMeasureArcLength
MsdOimBaliAndChainAlignment
msdDimBallAndChainAlignmentAuto
msdDimBallAndChainAlignmentLeft
msdDimBallAndChainAlignmentRight
0
1
= 2
252
MsdDimCustomSymbol
msdDimCustomSymbolCharacter
1
msdDimCusto mSym bolDefault
0
MsdDimDMSPrecisionMode
MsdDimDMSPrecisionModeFixed = 0
Msd Di mDM SPrecisionModeFloa t ing
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
msdDimNoteHorizontalAttachmentLeft
0
1
253
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
msdDimNoteVerticalJustificationCenter
msdD im NoteVert i calJust i f i cat ionDynam i c
msdDimNoteVerticalJustification Top = 0
2
1
= 3
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
2
1
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
255
256
257
258
259
260
261
msdOimTerminatorTypeCirc l e
3
msdOimTerminator TypeOot = 4
msdOimTerminatorTypeNone = 0
msdOimTerminatorTypeNote = 5
msd OimT erminatorTypeOrig in
3
msdOimTe rm inatorTypeStroke
2
MsdDimTextField
msdOimTextFieldLowerLimit
msdOimTextFieldMain = 0
msdOimTextFieldMinus = 2
msdOimTextFieldPlus = 1
msdOimTextFieldUpperLimit
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
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
MsdOimTextFrameTypeNone = 0
MsdDimTexUustification
msdOimTextJustificationCenter = 2
msdOimTextJustificationLeft = 1
msdOimTextJustificationRight = 3
Msd Di mTextLocation
MsdOimTextLocationAbove = 1
MsdOimTextLocationInline = 0
MsdOimTextLocationOutside
2
MsdOimTextLocationTopLeft = 3
262
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
msdD r awingModeXor = 6
MsdElementCachePurpose
msdElementCachePurposeControl
2
msdElementCachePurposeGraph i cal
4
msdElementCachePurposeNonModel = 1
MsdElementClass
msdElementClassConstruction
264
265
91
266
267
268
269
270
IThe Enumeration Li st I
271
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
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
MsdLevelChangeType
msdLevelChangeAfterChangeActive
2
9
272
5000
MsdMeasurementBase
msdMeasurementBaseDegree = 2
msdMeasurementBaseMeter = 1
msdMeasurementBaseNone = 0
MsdMeasurementSystem
msdMeasurementSystemEnglish = 1
msdMeasurementSystemMetric = 2
msdMeasurementSystemUndefined
0
MsdMem berTraverse Type
msdMemberTraverseCopy = 2
msdMemberTraverseDirectMembers
msdMemberTraverseEnumerate = 3
msdMemberTraverseManipulate = 1
msdMember TraverseSimple = 0
17
273
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
11
mdlModelChangeBeforeAct i ve
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
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
msdNestOverridesNever = 2
17
274
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
Msd RasterWorld File
msdRasterWorldFileHgr = 1
msdRasterWorldFileNone = 0
msdRasterWor l dFi l eWorldFile
MsdReferenceSystem
msdReferenceSystemDgn
275
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
msdStandardsCheckerRep l ac eChoiceSkip = 0
MsdStandardsCheckerReplaceOptions
msdStandardsCheckerReplaceOptionCanFix = 2
msdStandardsCheckerReplaceOptionCanIgnore
MsdStatusBarArea
msdStatusBarAreaLeft
16
msdStatusBarAreaMiddle = 15
MsdTagType
msdTagTypeBinary = 5
msdTagTypeCharacter = 1
msdTagTypeDouble = 4
msdTagTypeLonglnteger
3
msdTagTypeShortlnteger = 2
276
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
MsdV7 Action
msdV7ActionAskUser = 0
msdV7ActionUpgradeToV8
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
13
279
280
Notice how this method is asking for two Point3d Types Start Point and the other for the End Point.
281
282
I Review I
283
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
14
End S ub
285
286
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
287
Application
End Sub
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
288
15
Adding To Documents
We have created lines, circles, arcs, and text as we introduced
programming topics. Let's examine the specifics of adding elements and
other objects to our design files. We begin with graphical elements and
then work on non-graphical elements such as levels.
In this chapter:
~
Graphical Elements
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
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
I Graphical Elements I
291
292
y,
Exit Sub
End If
Dim LinePoirts() As Point3d
ReD i m LinePo i nts(O To (UBound(Po i nt El ems) + 1) \ 3) As Po i nt3d
Dim I As Long
Dim Po i ntCount e r As Long
Dim myLine As LineE l ement
For I = LBound( Poi ntEl ems) To UBound(Po i ntE l ems) Ste p 3
Li nePoints( PointCoun t e r ) . X Point Elems(I)
Li nePoi nts (Poi ntCounter). Y = Po i ntEl ems (I + 1)
Line Poi nts ( PointCo unter ) . Z = PointElems ( I + 2)
PointCounter = PointCounter + 1
Next I
Se t myLi ne = CreateLineElement1(Nothing, LinePoints)
Act i veModelReference . AddE l emen t my Li ne
En d Sub
I Graphical Elements I
293
6 We use CreateL i neEl ementl, using the points created from the
ParamArray.
7
Create3d Lines
Create3dLines
Create3d Li nes
Create3dLines
Create3dLines
End Sub
0,
0,
0,
0,
0,
0,
0,
4,
4,
4,
0,
0,
0,
0,
4 , 0 , 0 , 4 , 4, 0 , 0 , 4, 0 , 0, 0,
4, 4 ,
4, 0,
4,
Once a line is created, we can make changes to its properties such as its
color, level, or linestyle properties.
294
,
OK
Cancel
In MicroStation's Color
Table dialog box, if we
scroll over the colors in
the table we see the
color number and the
RGB values for each
color. In the graphic
shown we can see that
color number 3 has an
RGB value of (255, 0,
0).
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
Set myLine2 = CreateLineElement1(myLine. LinePoints)
ActiveModelReference . AddElement myL i ne2
End Sub
In this example, we added one line of code, removed one line of code,
and made a slight change to another line. Here is the line we changed:
Set myLine2
CreateLineElement1(myLine. LinePoints)
Creating Shapes
A shape is a series of lines that are joined together into one element.
Here is the declaration for CreateShapeElementl:
~
296
I Graphical Elements I
297
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
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.
~
298
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
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)
CPo i nt.Y
StPoint.Y + (EnPo i nt.Y
StPoint . Y)
CPoint . Z StPoint . Z + ( EnPoint.Z
StPo i nt . Z)
CirRad = Po i nt3dDistance(StPoint, EnPoint) / 2
Set myEll i pse = CreateE llip se Elemen t 2(Not hi ng,
Ci r Rad, Ci rRad ,
Act i veModelReference.AddE l ement myEllipse
End Sub
2
/ 2
/ 2
/
CPoint, _
rotMatrix)
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 TestCreateE ll ipseA ()
Dim CPo i nt As Po i nt3d
Dim myEllipse As EllipseElement
Dim r ot Mat ri x As Mat r ix3d
CPoint . X = 2.5 : CPoint.Y = 2 . 5
Set myE ll ipse = Crea t eE l l i pse Elemen t 2(Noth i ng , CPo i nt , 1, 0. 5 , _
rotMatrix)
ActiveModel Ref erence . Add Element myEllipse
End Sub
Sub TestCreateEll i pseB ( )
Dim MajorA1 As Point3d
Dim Maj orA2 As Point3d
I Graphical Elements I
301
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.
302
I Graphical Elements I
303
Creating Text
Text is easy to create by using the CreateTextElementl method.
~
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
Se t myText
Next
End Sub
~Note
1.:
iN. ote
.2:
.
. I
iNote 3:
I
4 :
N. ote ,:
INoteS:
!
-----------'-6'-- -- - ------+-. ----ote
.i
,
" .
,
,
. . .. ..... t
"N-'---! .
..
'Note 7:::
I!
-"'-.-:-------------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.
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
0))
0) )
0))
0) )
0) )
0) )
0 , 0))
4 , 0))
4 , 0))
0, 0))
4, 0 ))
307
2 : Or i g i nPo i nt . Y
0))
Cel~Elements,
myCell
myCell . Redraw
App li c a t i on . AttachC e l l Li br ar y "Mi c ro St a ti on VBA . c e l "
Application.AttachedCellLibrary.AddCell myCell, _
"Box3 ", " Box3" , False
End Sub
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
Description
:.
:.
Annotation
, Where
Active Cells
EJacement
Terminator
I 80x3
I NONE
Point
Pgttern
I Element
I NONE
308
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
Name
h':)fll; l :dgn
309
Size
34 KB
34KB
34 KB
34 KB
34 KB
34 KB
34 KB
34 KB
34 KB
<'
Type
34 KB
'-',,_-'.L" '"'"'"'=c.:;C"~C'.C-'==.
>
v
-
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
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
[B
Using ScanCriteria
[B
[B
[B
TestScanAllA ()
Dim myElement As Element
Dim myEnum As ElementEnumerator
311
312
97
66
96
96
96
96
66
66
6
4
."' .!
313
91
314
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
315
,'~
@' Subtype
-.,~
,'~ T ransiorm
@' Subtype
_,~ Transiorm
@' Type
@I URL
@' URLTitie
@j' Vertex
SetXData
@' Type
@ URL
~@' URLTitle
'"
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
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
318
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
I Using ScanCriteria I
319
my Fi 1t e r . Inc 1udeL eve 1 Act i ve Des i 9n Fi 1e . Level s ( " SID EWA LK" )
myFilter.lncludeColor myColor - 1
Set myErum = ActiveModelReference.Scan(myFilter)
While myEnum . MoveNext
ElementCounter = ElementCo unte r + 1
Wend
MsgBox ElementCounter & " elements found. "
End Sub
320
321
322
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.
323
Elementcache!ElemenlCac I
Adding a watch to
t he variable
myCo llection
shows somet hing
like th is:
Cache Index
18
Long
Class
msdElemenlClassPrimary
MsdElemenlClass
Color
Long
DateLastModified
#9120120055:26:39 PM#
Date
FilePosrtion
4000017
Long
GraphicGroup
Long
HasAnyTags
False
800lean
InDisplaySet
True
800lean
IsComponentElement False
800lean
IsFromAttachment
False
800lean
IsGraphical
True
800lean
IsHidden
False
800lean
IsLinear
False
800lean
Is Locked
Fals e
800lean
IsModified
True
8 00le an
IsNew
True
8 00lean
IsSnappable
True
800lean
IsValid
True
Level
Linestyle
LineWeight
800lean
Leveillevel
LinestylellineStyle
ModelReference
Long
ModelReference!ModelRel
Subtype
Type
msdElementTypeSharedCe l1
MsdElementType
I
I,
URL
string
URLTrtle
string
Var iantlOiJjecl!Element
Var iantlObject!Element
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 Tes t ScanFi l terM ()
Dim myEnum As ElementEnumerator
Dim myFilter As New ElementScanCriteria
Dim myGroup As NamedGroupElement
Set myGroup = ActiveModelReference.AddNewNamedGroup( "GroupA " )
myFilter . ExcludeAllTypes
myFi 1ter. Excl udeA 11 Level s
myFilter . lncludeType msdE l ementTypeSharedCe l l
my Fi 1t e r . Inc 1udeL eve 1 Act i ve Des i 9 n Fi 1e . Level s ( "C0 LUMNS " )
Set myEnum = ActiveModelReference . Scan(myFilter)
While myEnum . MoveNext
myGroup . AddMember myEnum.Current
Wend
324
325
326
IncludeOnlySolid()
IncludeOnlyUn l ocked()
IncludeOnlyUnmodified()
IncludeOnlyUserAttribute(UserAttributeID As Long)
IncludeOnlyVisible()
IncludeOnlyWithinRange(Range As Range3d)
IncludeSubtype(Long As Long)
Inc l udeType(Type As Msd El ementType)
Reset()
A review of the MicroStation VBA help file explains any of the methods
that are not self-explanatory. One method is worth noting: the
"IncludeOnlyWithinRange" method.
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
17
Interactive Modification
User interaction can be helpful when modifying files and elements in
VBA. When our programs are designed well, they are powerful and
flexible.
In this chapter:
[8
[8
[8
[8
[8
[8
[8
329
330
Prompt
Status
ro'"
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.
Sub TestShowTempMe ss age ()
ShowTempMessage msdStatusBarAreaLeft, "Message Left."
ShowTempMessage msdStatusBarAreaMiddle, "Message Middle."
End Sub
: Eile
~dit
: ~ lroe;aU-lt ------.;JI 0
1D
~ Q i~ I ~ ~
ft II<)
331
IMndow tielp
. 1_
".
:::.:::
00
ItQ i ?
.1~
11J~ 1 ~:"Ij
,
;... : CJ
2} .. :.
o
]JJ',
J.
A!- .
5',
.I. ~
.GJ~ E-
7~
~-,
Sub TestShowTempMessageCenter ()
ShowTempMessage msdStatusBarAre aMi dd l e. "Changes made to file :" , _
332
'"
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
333
myElement.Rewrite
Wend
End Sub
changes
all
selected
elements to the active color in MicroStation if
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
~SER INPUT
Thus far we have discussed prompting the user with information and
working with previously-selected elements. Allowing the user to give us
input as our procedures execute makes our interactive modifications
more powerful.
The Cad Input Queue allows us to capture some of the user's interaction
with MicroStation. Let's look at a few examples of using the CAD Input
Queue. We begin with a very simple example that demonstrates the use
of the CAD Input Queue and then move to some real-world examples.
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
335
msdCadlnputTypeCommand
1
msdCadlnputTypeReset = 2
msdCadlnputTypeOataPoint 3
msdCadlnputTypeKeyin = 4
msdCadlnputTypeAny = 5
msdCadlnputTypeUnassignedCB 6
336
337
This pro cedure captures ten inputs or captures until a reset is detected.
Point
Point
Command
Command
Command
Keyin
Point
Point
Command
Point
<,
11581.8836494914
27463.2962386063
0
1
9599.68844328587
28602.2371305697
0
1
PLACE SMART LINE
PLACE BLOCK ICON
CGPLACE CIRCLE ICON
bogus keyin
10796.1239475839
31518.0353275433
0
1
10664.7076908189
30833 . 5756568922
0
1
MOL KEYIN lv l mang~ levelmanage~ dialog open
11195.8483952442
310 1 9 . 7486873093
0
1
"-
377 579 0
196 475 0
168 238 0
144 363 0
241 329 0
v
'!'
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.
338
Te s t Cad I n putE allows the user to select two points. A line is then
drawn between these two points. A careful examination of the code, and
339
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
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
341
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.
Function PointsByLine () As Point3d()
Dim myCIO As CadInputOueue
Dim myCIM As CadlnputMessage
Dim pt3Start As Point3d
Dim pt3End As Point3d
Dim selPts(O To 1) As Point3d
Set myCIO
Cad l nputOueue
Set myCIM = myCIO . GetInput(msdCadlnputTypeDataPoint. _
msdCadlnputTypeReset)
Select Case myCIM . InputType
Case msdCadInput TypeReset
Err . Raise - 12345
Exit Func t ion
Case ms dCad Inp ut TypeDat aPoin t
pt3Start = myCIM . point
End Select
CadlnputOueue . SendCommand "PLACE LINE "
Cad l nputOueue . SendDataPoi nt pt 3Start
Set myCIM = myCIO . GetInp ut(msdCadInputTypeDataPoint . _
msdCadInputTypeReset)
Select Case myCIM . InputType
Case msdCadInputTypeReset
342
After the user selects the first point, we begin the "PLACE LINE"
command and supply the command the point the user selected. This
creates a rubber-band effect that allows us to see the first point selected
and also shows the cursor's coordinates as it waits for the second point
to be selected. After the second point is selected, we place the selected
points into an array that is used for the return value of the function . If
the user issues a reset while the first or second points are entered, we
raise an error so the function or procedure that called Poi nt sByLi ne"
function will know what happened. We need to remember that the
"PLACE LINE" command is still in process as we exit the function. We
will handle it in the calling procedure or function as follows :
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
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
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
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
345
& se l Pts(l) . Z
Ex it Sub
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
;t:o.~.~
II:
;~;-\
i
!1~,4\
!
:/o tl~~~_~]G100 0 : .~~~~=~' cR0i'J ICE ~ ._~ _._,_...J G1e
:
! ':
(i
I~
C .
NOTLEY,,
: . \r---,-
;;
.'
II
\ TABOR,Co
11 0
:; , '
r==r'
i;
~< ,
\ SE Yf
- - ' TJ
;,'
: 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)
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.
Here is the
output for the
office.dgn file
installed with
MicroStation:
ole
!;.dit
pffi ce.
PART
GWALL
PART
URINAL
PART
URINAL
DPART
DPART
POOORR
RAIL2
RAIL1
.~
FQ.rmat
\lJew
tielp
dgn
16233.3074154912
16233.3074154912
16233.3074154912
16233.3074154912
16233.3074154912
16233.3074154912
14517.3074154912
14517.3074154912
14517.3074154912
16233.3074154912
16233.3074154912
17003.6804376836
16427.6804376836
17819.6804376836
17411. 6804376836
18635.6804376836
18227.6804376836
16991.6774376836
15851. 6804376836
15917.6804376836
16991. 6774376836
15651. 6804376836
o
o
o
o
o
o
o
o
o
o
o
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
From the VBA Project Manager, select the VBA Project in which we
are currently working and then click the record button.
I Using SendCommand I
349
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
Coordinates are in master units
startpoint . X 16735 . 231975
startpo i nt.Y
33020 . 733029
sta r tp oint.Z
0#
Se nd a data po i nt to the cu r rent command
point. X sta r tPo int. X
point . Y = startPoint . Y
point . Z = startPoint . Z
Ca d InputOueue.SendDataPoint point. 1
point.X
startPoint.X + 1985 . 401024
point . Y startpoint . Y 610 . 892623
point.Z
startPoint . Z
CadInputOue ue . SendDataPoint point. 1
Send a reset to the current co mmand
CadInputOueue.SendReset
Comman dState . StartDefaultComman d
End Sub
350
We have now stripped down this macro to the bare essentials. The
coordinates for the line have been replaced with (0, 0, 0) and (4, 5,6).
Let's record another macro. This time we will record drawing a Block
(rectangle).
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"
Coordinates are in master units
startPoint . X 3 .1 96418
startPo int.Y
6 . 071205
startPoint.Z
0#
Send a data point to the current command
point.X
startPoin t. X
point.Y
startPoint.Y
point.Z
startPoint.Z
Cad l nputOueue . SendDataPoint point, 1
point.X = startPoint.X + 2.537984
point.Y = startPoint.Y - 0.882104
point.Z = startPoint.Z
Cad lnput Oueue.SendDataPoint point, 1
CommandState . StartDefau lt Command
End Sub
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 Macro2 modi f iedB ()
Dim point As Point3d
Di m myCIO As CadlnputOueue
Dim myCIM As CadlnputMessage
Set myCIO = CadlnputOueue
Set myC IM = myCIO . Getlnput(msdCadlnputTypeDataPoint )
point = myCIM.point
CadlnputOueue . SendCommand "PLACE BLOCK ICON "
CadlnputOueue.SendDataPoint point. 1
point.X = point.X + 2.5
point.Y = point . Y - 0.75
CadlnputOueue.SendDataPoint point.
CommandState.StartDefaultCommand
End Sub
Now the first point used for the block is entirely based on user input.
The second point is still relative to the first point.
Recording macros is one way to discover the command names of
MicroStation commands. The following macro is another way.
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
digilizer
dimcreale
dimension
dims lyle
displaysel
ri!~
~I
BJ
palette
parlicielrace
plol
popsel
dialog openfile
dialog drawing scale open
dialog dr awingscale
delele
erase
bogus keyin
353
frmMatchProperties.frm
The
first
form,
"frmMatchProperties.
frm", looks like this:
r :source Element:~..,..-,--,-,--,-~ ~-:-:t !:-: De,stination Element(~): ~:-:-:- t
The
form
looks
::
Seled
i: I: Change Current Selection :
simple enough. We
r I
I: : 0 Element(s) modified: ,
'
:'Level
have a few command
buttons, a couple of
frames, a handful of
ILineweight r I
,': h-,:- .' .' , : ,: ,: ,: ,:::,J.
check boxes, a label,
Close
and four text boxes.
Before we look at the
code behind
the
controls, let's discuss the program's desired functionality.
:: ,. ~ :
ll
L'
:i:
:;
::
.:.:
'.,
354
The user can select which of the properties from the source element
are to be changed in the Destination Elements.
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
355
Control Properties
1
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.
356
Get the level (if a level is assigned to the element). The level name is
placed in the appropriate text box.
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.
357
tx t Lineweight . Text
End Sele ct
E1 s e
358
Close Button
The Close button unloads the Form.
359
As the user moves the cursor around the fo rm and the fram es, we do not
want to display anything in the prompt because clicking on the fo rm or
frame does not do anything. So, we use ShowPrompt with an em pty
string so nothing displays.
Private Sub btnSelectSource_MouseMove(ByVal Button As Integer ,
ByVal Shift As Integer, ByVal X As Single, _
ByVal Y As Single)
ShowPrompt "Select a single "" Source "" Element :"
End Sub
Private Sub btnChange_MouseMove(ByVal Button As Integer, _
ByVal Shift As Integer , ByVal X As Single, _
ByVal Y As Single)
360
As the user moves the cursor over the command buttons, we want to let
the user know what happens if the button is clicked. We already do this
with the ControlTipText property of each button but using the prompt
more closely reflects MicroStation standard functionality.
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.
Private Sub UserForm_Initia l ize()
ShowCommand "VB A Match Properties:"
End Sub
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
IB vbFormCode
=0
=1
IB vbApp Windows
=2
IB vbAppTaskManager
=3
361
In this program we are not concerned with how the form is closed, only
that it is closing.
Private Sub UserForm_OueryClose(Cancel As Integer. _
CloseMode As Integer)
ShowPrompt ....
ShowCommand
End Su b
The procedure Tes tMatc hPr operti es, if placed in a code module, is
available to the user through the VBA Project Manager or from the
MicroStation menu Utilities> Macro> Macros or by pressing the <F8>
key while holding down the <Alt> key (<Alt + F8.
362
v,..,..~"""'. ".~.~ry;~'\?~
~ '-'''-"'
<
<i,~>t~:;;~:~~~~~
- Destination Element(s)
"' Select
Level
r-" '-'-',
"
f"l,
,I,
oElement(s) modified,
II
I:::' _~B
.-
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
alignment
and
distribution
~
1.--,-0-,'- - - - - operations on selected text in
MicroStation. Since we want to
allow the user to select a point to
align to, the form needs to be
Distribute Vertically
displayed as modeless. This
program
involves
geometric
calculations and movmg text
elements based on those calculations.
M
<
Desired Functionality
~
[B
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.
Pr i vate Sub bt nPi ckBasePo in t Click()
Di m myCIO As Cad l nputO ueue
Di m myCIM As Cad l nputMessage
Set myCIO = CadlnputOueue
Set myCIM = myC IO. Getlnput(msdCadlnputTypeDataPoint . _
msdCad l nputTypeReset)
Do
364
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.
Priva t e Sub txtX_KeyPress(ByVa l KeyAsc ii As MSFor ms . Ret urn I ntege r )
Select Case KeyAsci i
Case Asc( "O" ) To Asc( "9" )
Case Asc( " . " )
If I nStr ( l. txtX .T ext . "." ) > 0 Then
KeyAscii = 0
End If
Ca se Else
Ke yAscii
0
End Se l ect
En d Sub
365
The KeyPress event tells us the ASCII character code of the keyboard
character that was pressed. If we change the Key Ascii parameter to a
value of zero (0), it is as though the key was never pressed. So, we look at
the KeyAscii parameter and ask ourselves the following questions with
the following results:
[8 Is the Key Ascii between the numbers 0 to 9? If so, do nothing.
366
Now when we declare our procedure to align the selected text, it looks
like this:
Sub Ali gnSelected COptiona l ElemAlignMode As AlignM ode = _
msvbaAlignModeLeft)
o
Pci vate Su b btnA 0
msvbaAli gnModeLeft
msvbaAlignModeR ight
11!lIIModeLeft])
(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:
Dim pt3BasePoint As Point3d
When the user selects a point, we use this variable to store the selection.
Here is the code that actually aligns the text left, center, or right:
Sub AlignSelectedCOptional ElemAlignMode As AlignMode = _
msvbaAlignModeLeft)
367
myText Elem.Boundary.Low . X. 0)
my Tex t Ele m.Rew r i t e
Case msvbaA li gnModeRight
myTextElem . Move Point3dFromXY(pt3BasePoint . X
yTextElem . Boundary .L ow . X - _
(myTextElem . Boundary . High.X - _
myTextElem.Bou nd ary . Low.X) / 2. 0)
myTextElem.Rewrite
End Select
End Select
Wend
End Sub
368
Degrees of Complexity
There are three degrees of complexity in this program. The degrees and
their tasks are as follows:
Low:
Medium:
High:
...-._.
369
After the user selects the text, we want even spacing between the top
and bottom elements without those elements moving.
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.
text elements.
[B Determine the vertical order in which the text elements appear.
[B Determine the number of selected text elements.
370
We have created this function to allow for future use and expansion with
other types of Elements. We ask for the element type and the elements to
be considered. From these parameters, we discover the Min and Max
values and return them as an array of Point3d types.
The next task is to sort the elements vertically. This is accomplished by
providing the type of element we want to look at and the elements to be
considered. We return the elements in their vertically sorted state as an
array of elements.
Function SortElementsVertically CElemType As long, _
Elements I n As Variant) As ElementC)
Dim I As l ong
Dim boolMadeChange As Boolean
Dim lngE l emIDC) As Dlong
Dim pt3BoundPtC) As Point3d
Dim myTextElem As TextElement
Dim myTextElem2 As TextElement
Dim tmpID As Dlong
Dim tmpPt As Point3d
ReDim lngElemIDCO) As Dlong
ReDim pt3BoundPtCO) As Point3d
For I = lBoundCElementsIn) To UBoundCElementsIn)
Selec t Case ElemType
Case msdElementTypeText
If El ements I nCI) .Type = msdElementTypeText Then
Set myTextElem = ElementsInCI)
lngElemID CUBoundClng ElemID)) = myTextElem . ID
371
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
End Function
Elems I n
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
Dim
Dim
Dim
Dim
I As l ong
boolMadeChange As Boolean
lngElemID() As Dl ong
pt3BoundPt () As Poi nt3d
myTextE l em As TextEleme nt
372
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.
373
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
Next I
SortElementsVertically
Elemsln
374
The previous three functions are written so that they can be expanded in
the future. We do not need to write code right now to accommodate
these potential future needs.
Now we need to make use of these functions in a single procedure to
accomplish our "Distribution" task.
Private Sub btnDistributeVert_Click()
Dim MyPts As Variant
Dim pt 3Sta rtP oi nt As Poi nt3d
Dim pt3EndPoint As Point3d
Dim myElemEnum As ElementEnumerator
Dim myElem As Element
Dim myElems ( ) As Element
Dim I As Long
Di m myTextElem As TextElement
Dim lngSpaces As Long
Dim dblSpacePerEle ment As Double
Di m sortElems() As El ement
Set myEle mEnum = ActiveModelReference.GetSelectedElements
myEl ems - myElemEnum . BuildArrayFromContents
MyPts = GetMinMaxY(msdElementTypeText , myEl ems )
lngSpaces = Ge t Se l ectedCount (msdElementTypeText , myEl ems ) - 1
If lngSpaces > 1 Then
dblSpacePerElement = (MyPts (O) . Y - MyP ts(l ) .Y ) / l ngSpace s
375
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.
376
At this point, this code spaces text evenly if the text elements are the
same height. The upper-left corner of each element is what we are using
to space these text elements. If one text element is larger than the others,
it could run into the text below it because we are only considering the
spacing between the top -left corners relative to each other, not the topleft corner of one text element with the bottom-left corner of the one
above it. We will leave the expansion of this macro to accommodate the
text height to the reader of this book.
377
frmExportElements.frm
The frmExportElements.frm User
Form accomplishes a simple task:
it exports elements on specific
levels to a new design file.
Levels ..
Control Names
IB 1st Levels
IB txtFileName
.. . . . .
... ..
File Name : .
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.
Private Sub UserForm_In i t i alize()
Dim my Level As Level
Dim LevelNames() As String
Dim MadeC ange As Boolean
Dim tmpName As String
Dim I As Long
ReDim LevelNames(O)
For Each myLevel In ActiveDesignFile.Levels
LevelNames(UBound(LevelNames)) = myLevel . Name
378
1 The n
When comparing numeric values, we can use greater than ( and less
than ) comparisons. You can also do this with text but the results are
not always what we expect. So, we employ the standard VBA StrComp
function to compare two strings.
Private Sub btnExport_C l ick()
Dim myFileName As String
Dim myNewFile As DesignFile
Dim I As Long
Dim ElemID As DLong
Dim myE l ems() As Element
Dim myElemEnum As ElementEnumerator
Dim my Level As Level
myFileName = txtFileName.Text
If ActiveModelReference.Is3D Then
CreateDesignFile "seed3d ". myFileName. False
Else
CreateDesignFile "seed2d " . myFileName. ralse
End If
Set myNewFile = OpenDesignFileForProgram(myFileName)
Dim mySelCriteria As New ElementScanCriteria
mySelCriteria . ExcludeAllLevels
379
380
381
Levels
File Name
I c: \~licroStation
frmDFAV.frm
VBA\exporttest.dgn
Export
r;;
.
Include Sub-Folders
..
..
. .. .. . . . .. . .
382
txtFolder
[B
btnBrowse
[B
lstFiles
[B
lstAttachments
!I..
My Documents
$ .S iifill "I.IIIM
. $ .....
ffie
!I
IQ Administrator's Documents
8:J .. !ClJ
Guest's Documents
M\I
l\I,:Ih~lnrl.. PI~rp<:
Cancel
Edit
View
Favorites
d CJ
L 6
CJ
Help
!I CJ XM_Addln_JW
tED
Viewpoint
,?'!i !
-
~"
Name
n~('D~f~~it)1
i '] i~'~i~d~"S'~bs
-=:
'I fiii"lPath
,..y ,) CJ
; Type
Data
' REG~SZ
REG_SZ
True
REG_SZ
C:\Microstation VBA
~ly Computer\HKEY _CURRENT _USER\Software\VB and VBA Program Settings\VBA File Attachment Viewer\Defaults
Program Components
[B
[B
[B
[B
[B
383
When the form is initialized we look for the saved settings and put them
in.
If we find a "path" saved in the registry, we set the checkbox value and
populate the file list using our PopulateFileList method.
384
Cons t
Const
Const
Const
Const
Bif _NewDialogSty l e = 64
Bif - UseNewui = 80
Bi f _BrowseForComputer = 4096
Bif_BrowseForPrinter = 8192
Bif - BrowseIncl udeFi 1es = 16384
After the constants, types, and functions are declared, we can use them
in our code. Here is the click event of the Browse button.
Private Sub btnBrowse_Cl i ck()
Dim MyBI As Browselnfo
Dim FList As Long
Dim DirName As String
Dim SelFolder As Long
DirName = Space(255)
MyB I.sTitle = "Select Root Folder: "
MyBI.sDisplayName = Space(255)
MyBI.ulFlags = Bif_Retu r nOnlyFSDirs
FList = SHBrowseForFolder(MyBI)
SelFolder = SHGetPathFromIDList(FList, DirName)
DirName = Left (D irName, InStr(l , DirName , Chr(O)) If DirName <> "" Then
txtFol der . Text
DirName
Else
txtFolder.Text
End If
PopulateF il eL i st
End Sub
1)
385
available References:
OK
Cancel
~rowse",
Priority
tielp
.S 'L.........x.".~"..._......._....... _1
Microso ft Scripting Runt ime
Location:
C: \ WINDOWS\System32\scrrun ,dll
Language:
Standard
386
The first thing Fi 1e sIn Fold e r does is looks for files in the "Folder In"
parameter folder. We look at the file extension to see if it matches the
FileExtension parameter. If it does, we add it to the list. After all files
have been reviewed, we check if we should also look at sub-folders. If we
are not to look at sub-folders, we complete the function and move on. If
we are to look at sub-folders, we begin a For ... Each statement to look at
each of the sub-folders in the current folder.
For each sub-folder we find using Fi 1es InFo 1der, we call Fi 1es In Fo 1de r
using the sub-folder as the FolderIn parameter. This is why it is
recursive. The procedure calls itself. When dealing with recursive
procedures or functions, we need to be sure there is a way to finish
execution. Otherwise, we could end up with hundreds or thousands of
procedures in the call stack with no ending to the execution.
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.
Pri va t e Sub l s t Fi les_Cl i ck()
l s t Attach ments . Cl ea r
I f l stF il es .T ext <> "" Then
Dim my DesF il e As DesignF il e
Set myDesFile
Before looking at the attachmenls of a file, we need to open the file. Vie
have two ways to open the file: open it for the user to see and work with
or open it so the user does not see the file but our program can work
with it. In this example we are using OpenOesi gnFi 1eForProgram to open
387
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.
Private Sub UserForm_OueryClose(Cancel As Integer, _
CloseMode As Integer)
SaveSetting "VBA File Attachment Viewer", "Defaults", _
"Path ", txt Fold er. Text
SaveSetting "VBA File Attachment Viewer ", "Defaults " ,
" Inc l ude Subs ", _ chkSubFolders.Value
End Sub
We are saving two settings to the Windows registry. These are the
settings read by the initialize event of the form.
INTERACTING WITH
MOL ApPLICATIONS
388
End Sub
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
End If
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
Pr ivat e Sub IM oda IDi alogEvents_OnD ial ogC l osed(ByVal _
DialogBoxName As String . ByVal DialogResult As _
MsdDialogBoxResult)
End Sub
Private Sub IModaIDial ogEvents_OnDialogOpened(ByVal _
DialogBoxName As String . DialogResult As MsdDialogBoxResult)
If DialogBoxName = "Select Image File " Then
CadInputOueue.SendCommand _
390
The path and filename is no longer hard-coded. This means we can use
this class module any time we want to insert an image into a file. This is
how it is used:
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
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
What is an interface? The term is used in programming to describ e
several different things, so lets explain and define the term.
We have already worked with user forms and controls to create a
graphical user interface, which allows users to interact with controls.
The graphics provide an interface to the code of the program.
Another type of interface allows us to interact with code in a program
but does not have a graphical component. It allows us to interact with
the user's activities in MicroStation. For example, when a user selects an
element in MicroStation, we can capture that activity through the use of
an interface named "ILocateCommandEvents". As the user picks points
in MicroStation, we can capture those points through the use of the
"IPrimitiveCommandEvents" Interface.
User interaction with some dialogs in MicroStation can be evaluated
through the use of the "IModalDialogEvents".
In this chapter:
[B Interface basics
[B Class module review
[B Class module life cycle
[B The dynamics event
391
392
IPrimitiveCommandEvents interface
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 IPr imi tiveCommandEvents
Implements
393
394
1':
After a class module is inserted and named, we begin writing our code.
Methods and functions are written very much like they are in code
modules. We can create events for our class modules. We can create
properties by declaring variables as "Public" in the General Declarations
area of the code module. And we can also create properties through the
use of "Get" and "Set" (or "Let") statements.
The end result of creating a class is a new object. Classes cannot operate
independently. They need other code to initiate them, set their
properties, and use their methods. I will demonstrate two ways to call up
a class module. The first is to create a new class module named
"clsNetNode". Here is the code:
Pr iva t e Type IP Add r
Se tl As Byte
Set2 As Byte
Set3 As By t e
Set4 As Byte
End Type
Public Name As St ring
Pr i vate IPAdd r ess As IPAddr
SubP i ng()
MsgBox "Pinging " & IPAddress . Setl &
&
IPAddress . Set2 &
&
IPAddress . Set3 &
&
IPAddress.Set4 , , Name
End Sub
Sub SetIPAddress(IPA As Byte, IPB As Byte , IPe As Byte, _
IPD As Byte)
PAddress.Setl = IPA
395
IPB
I Pe
IPD
This class has one property (Name) and two methods (Ping and
SetIPAddress). The SetIPAddress method sets the IP address values of
the private variable "IPAddress". The Ping method displays the entered
IP address in a MessageBox and uses the Name property for the
MessageBox caption.
The first way to call up a class module is to declare a variable as the class
type, set the variable to a "New" class type, and then set properties and
use methods.
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
396
interfaces.
The
first
is
the
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
[EJ
397
398
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.
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
Tong e nt
Here are the
screen shots of
the program
working. Notice
the command
and prompts
guiding the user.
TANGENT
Element Selection> Identify efement to add to set
401
402
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 o ca~i Oflt<
3 . 08 7
L oca ti on
A
Here is the code for the Class Module named LeE DistanceText.
Implements ILocateCommandEvents
Private selElem As Element
Private pt3StPoint As Point3d
Private dblDistance As Double
Private Sub ILocateCommandEvents_AcceptCByVal Element As Element. _
403
CreateTextElementl(selE l em , Round(dblDistance, _
3) , Po i nt, rotMatrix)
ActiveModelReference.AddElement txtElem
txtEl eli. Rewri te
txtElem.Redraw
CommandState.StartLocate Me
End Sub
=
CreateTextElementl(selElem , Round(dblDistance, 3) , _
Point, rotMatrix)
tmpTxtElem.Redraw DrawMode
ShowPrompt "Select Distance Point: "
End Sub
Private Sub I LocateCommandEvents_ LocateFailed ()
CommandState . Start Locate Me
End Sub
Private Sub ILo cateCo mmand Ev ents_Locate Fi lter (By Val Element As Element, Point As Point3d,
Accepted As Boolean)
Set selElem = Element
pt3StPoint = Point
CommandState . StartDynamics
End Sub
Private Sub ILocateCommandEvents_LocateReset()
CommandState . StartDefaultCommand
End Sub
Private Sub ILocateCommandEvents_Start()
ShowCommand "Te xt Distance "
ShowPrompt "Select Element for Base Point "
End Sub
404
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.
I mpl ements IL ocateCommand Events
Pr i vate Sel El eme nt As El ement
Di m my LC As Lo cat eCri te r i a
Private Sub ILo cateCommandEvents _Accept(ByVa l Ele ment As Element . _
Point As Po i nt 3d .
By Val Vi ew As View )
End Sub
Private Sub I LocateCommandEvents_C l eanup()
End Sub
Private Sub ILocateCommand Events_Dynamics(Point As Point3d. _
ByVa l View As View. ByVal DrawMode As MsdDrawingMode)
End Sub
Pr i vate Sub I LocateCommand Events_LocateFailed()
If SelElement Is Nothing = False Then
405
406
Sub ExcludeAllTypesO
[B
[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
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
407
[B
[B
[B
[B
[B
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:
Implements IPr i mitiveCommandEvents
Dim pt3BasePoint As Po in t3d
Dim boolSet As Boolean
Private Sub IPrimitiveCommandEvents_Cleanup()
End Sub
Private Sub IPrim i tiveCommandEvents_DataPoint(Point As Point3d , _
ByVal View As View)
If boolSet = False Then
pt3BasePoint = Point
CommandState.StartDynam i cs
boolSet = True
Else
CommandState . StartDefaultCommand
End If
End Sub
408
CreateLineElement2(~othirg,
pt3BasePoint, Point)
myLineElem.Redraw DrawMode
End Sub
Private Sub IPrimitiveCommandEvents _Keyin(ByVal Keyin As String)
End Sub
Private Sub IPrimitiveC ommandEvents_Rese t ()
End Sub
Pr i vate Sub I Prim iti veCommand Eve nts_St ar t()
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 timeconsuming. 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
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
Private Sub IPrimitiveCommandEvents_Cleanup()
End Sub
Private Sub IPrimitiveCommandEvents_DataPoint(Point As Point3d. _
ByVal View As View)
If boo lS et = False Then
pt3BasePoint = Point
CommandState . StartDynamics
boolSet = True
E1 s e
CommandState.StartDefaultCommand
End If
End Sub
Private Sub IPrimitiveCommandEvents_Dynamics(Point As Point3d. _
ByVa l View As View. ByVal DrawMode As MsdDrawingMode)
Dim pt3RecPoints(D To 3) As Point3d
Dim myShapeElem As ShapeElement
pt3RecPoints(O) = pt3BasePoint
pt3RecPoints(1).X
Point.X
pt3RecPoints(1).Y = pt3BasePoint . Y
410
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 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
411
This example makes use of the Reset event. If the user resets the
command, we exit the interface object by calling StartDefaul tCommand .
412
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:
Im pl ement s IP rimit iv eComm an dEv ent s
Dim pt3BasePoi nt As Point3d
Dim boo l Se t As Bool ea n
Pub li c Ve rt i ces As Long
Private Sub IPrimitiveCommandEvents_Cleanup()
End Sub
Private Sub IPrimitiveCommandEvents_DataPoint(Point As Point3d. _
ByVal View As View)
If boolSet = False Then
pt3BasePoint = Point
CommandState.StartDynamics
boolSet = True
Else
CommandState.StartDefaultCommand
End If
End Sub
413
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
Private Sub IPrimitiveCommandEvents_Keyin(ByVa l Keyin As String )
End Sub
Private Sub IPrimitiveCommandEvents_Reset()
CommandState . StartDefaultCommand
End Sub
Private Sub IPrimitiveCommandEvents_Start()
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
414
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
Pr ivate Sub IPrimitiveCommandEvents_Cleanup()
End Sub
Private Sub IPrimitiveCommandEvents_DataPoint(Point As Point3d. _
ByVal View As View)
If boolSet = False Then
415
CreatePointStringElementlCNothing, _
pt3Points, False)
Act i veModelRe f erence.AddElement myPoin t String
CommandState . StartDefaultCommand
End Select
End Sub
Private Sub IPrimitiveCommandEvents_Reset()
CommandState.StartDefaultCommand
End Sub
Private Sub IPrimitiveCommandEvents_Start()
ReDim pt3Points(O)
End Sub
The user is likely to enter more than one or two points when using this
example. We could declare a variable to hold up to 10 points or 50 points
or 100 points. We could then prompt the user to select "up to 10 points",
416
CreatePointStr i ngElementl(Nothing. _
Here is the code in the Keyin event. If the user enters "plclose': "PIClose",
"PLClose", etc., we close the point string by placing the base point in the
upper-bound element of the pt3Points variable. We then create a new
PointString element using the pl3Points variable for the vertices of the
point string. We have seen code similar to this but we need to add
something we have not done before. In addition to creating the Point
417
].
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
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
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:
Imp l ements I Pri mi tiveCommand Eve nts
Dim pt3BasePoin t As Point3d
Dim boo l Set As Boo l ean
Publ i c l ngDiv i s i ons As Long
Private Sub IPrimitiveCommandEvents_Cleanup()
En d Sub
Private Sub IPrimitiveCommandEvents_DataPo i nt(Point As Point3d. _
ByVal View As View)
If boolSet = False Then
pt3BasePo i nt = Point
CommandState.StartDynamics
boolSet = True
Else
Dim pt3EndPoint As Point3d
Dim dblLineAngle As Double
Dim dblSegDist As Double
Dim DivPoints() As Point3d
419
Di m I As Long
ReDim Di vPo i nts(O To lngDivisions - 2) As Point3d
pt3EndPoint
Point
cblLineAngle = Atnpt3EndPoint.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
Private Sub OrawCircle (CenPt As Point3d. Radius As Double)
Dim myEllipse As EllipseElement
Dim rotMatrix As Matrix3d
Set myEllipse
rotMatrix)
ActiveModelReference.AddElement myE llipse
End Sub
Private Sub 1PrimitiveCommandEvents_Dynamics(Point As Point3d . _
ByVal View As View. ByVal DrawMode As MsdDrawingMode)
Di m myLineElem As LineElement
Set myLineElem = CreateLineElement2CNothing . pt3BasePoint . Point)
420
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
421
12
422
False
5 We get the points that had been created by the selection of the two
points.
myDivPoints
423
Follow through the code in Pl aceL i ne3B. What is it doing with the points
returned by the PCE_LineTest3 Class?
What does this code do? Of course, we are using the PCE_LineTest3
class. But what are we doing with the returned points?
424
425
Point
Atn((pt3EndPoint.Y - pt3BasePoint . Y) / _
(p t 3En dPoi nt . X - pt3 Base Po i nt . X))
db'SegDist = POint3dDistanceXYCpt3BasePo'nt.
For I
pt3EncPoin~)
, _
lngDivisions
LBound(DivPoints) + 1 To UBound(DivPoints) - 1
DivPointsC I )
Point3dAddAngleDistanceCpt3Base Doint . _
426
CreateEllipseElement2(Nothing. myDivPoints(I) , _
0 . 25 , 0 . 25, rotMatrix)
ActiveModelReference . AddE le ment myEl li pse
Next
End Sub
427
Sub
IPrimit;veCo~na~dEvents_Cynamics(Poi~t
~rewMode
As
As Point3d, _
~sdDrawingMode)
Create a LineElement.
428
myLineElem.Redraw DrawMode
End Sub
Private Sub IPrimitiveCommandEvents_Keyin(ByVal Keyin As Str i ng)
End Sub
Private Sub IPrimitiveCommandEvents_Reset()
End Sub
Private Sub IPrimitiveCommandEvents_Start()
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.
429
=
Point
CommandState.StartDynamics
boolSet = True
E1 s e
CommandState . StartDefaultCommand
End If
En d Sub
Private Sub
As Point3d . _
ByVa l View As View . ByVal DrawMode As MsdDrawing Mode)
myLineElem.Vertex(l) = Point
myLineE l em .Re draw DrawMode
End Sub
IPr ' ~itiveCommandEvents _ 8yramics(Point
430
19
Using MicroStation's
Built-In User Forms
One ways to increase your speed in developing applications is to use of
existing code, objects, and interfaces.
In this chapter:
[B
[B
[B
[B
[B
[B
431
432
mdlDialog_openAltert
Lib "stdmdlbltin.dll"
As Long
433
Our first example prompts the user to select a file . We supply a file
extension, a default directory, and a dialog title.
Sub TestFi l eOp enA()
Dim strFName As String
Di m lngfhandle As Long
Dim l ngrid As Long
Dim retVal As Long
str FN ame = Space(255)
retVal = mdl Dialog_fileOp en(strFName , lngfhandle , lngrid, _
"*.d gn ", "C:\MicroStation VBA ",
"Ope n Fil e " )
Select Case retVal
Case 0 ' Open
strFName = Left(strFName. InStr(l. strFName . Chr(O) ) - 1)
MsgBox "File Selected: " & vbCr & strFName
Case 1 ' Cance l
MsgBox "No File Se l ected. "
End Select
End Sub
434
'>.;~)....~~"'",~':l "~...,.o:;:~,,"""
..
''''1~'
Ib
Look in:
Microstation V8A
vi
.... ~ ~
,"
"
'"'1'<~
<
() 1t f"
~'
.. ",t
...
rmJ
: ~~
GJ
~ filelO.dgn
~ filea.dgn
~ fileb .dgn
~ rast erdocs.dgn
e:i.~?~t.~j
ICl cd material
Ii::l Source Code
Re cent
, ft) pics
IC::ll docs
~ file l , dgn
~ file2.dgn
~ file3.dgn
, ~file4.dgn
~fileS.dgn
"
~file6.dgn
M~ Documents
~file7.dgn
. ~file8.dgn
~file9 . dgn
Desktop
M~ Computer
,
[
;
File name:
Files of \ype:
W,~,
M~
Network
Places
h... !
o apen as !ead-onl~
~.
Open
il
Cancel
I
,0>
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?"
435
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).
strFName = Le ft(strFName. InStr(l. strFName. Chr(O)) - 1)
MsgBox "File Selected :" & vbCr & strFName
File Selected:
C:\Microstation VBA\file4.dgn
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:
Sub TestFi 1 eOpenB ()
Dim strFName As String
Dim lngfhandle As Long
Dim lngrid As Long
Dim retVal As Long
436
Look in:
'j'!Q Fonts
!Q cd material
Recent
!!Q pics
@
Desktop
ll~file1.dgn
!iCl docs
I ~file2.dgn
l ~file3.dgn
Il
My Computer
~file4.dgn
~file5,dgn
II ;',
i ~file6 . dgn
. My Documents
~file9 .dgn
~filel0.dgn
~filea.dgn
~fileb . dgn
~ rasterdocs.dgn
l~ file7.dgn
I'
. 1________________________________________
I ~I
.. __Ivtl'._~!:~g!~ _I
Filename:
Files of lYpe:
------.-.-.--.------..-.---.----.-.---.-.---..-.--..'"':1
[.mmm! _
_
_
.v ;,
I
o
Open
Cancel
Open
;-J.; '"
f~.~ - C.:~i~rostation.~~~\:.
'.1;, .. ~
test4 .dgn
File not found.
please verify the correct file name was given.
The File Open dialog box does not allow anyone to "Open" a file that
does not exist. So, if we get a return value of 0, we can be sure that the
file name returned exists.
437
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)
438
Ib
Look in:
Mic,ostation VBA
IClFonts
;Qed material
QSouree Code
Recent
;Qpies
Fr~
o
,
~Book2.xls
~ Enums,xls
Desktop
r~'\
v:;:;
does
: ~Learn'ng
MS VBA.xls
.___My !'J.~~\oII.9.Lk__'
' "xis
. 0
I'"
Open
Cancel
'il
I
0 pen as read-only
Let's look at another example that displays more than one type of file.
Sub TestFi 1 eOpenD ()
Dim st r FName As String
Di m l ng fh andle As Long
Di m lngrid As Long
Dim ret Val As Long
strFName = Space(255)
retVal
439
440
The FileCreate dialog has the same look and feel as the FileOpen dialog
box.
Save jn:
r:J
Recent
@l
Desktop
"
'~
- 7'
My Documents
i '0
if , Fonts
[!Q cd material
IlrtJ Source Code
I
t~il 0
f} CO
ltl
~fileb.dgn
~ rasterdocs ,dgn
ii
i Ibpics
,Iro docs
I i ~ filel.dgn
I i~ file2 . dgn
I
l ~file3.dgn
1 ~ file4.dgn
il file5.dgn
't IM
, !~ file6 , dgn
i ~ '1 d
I l ilfl e7,gn
I[
: . ~file8,dgn
I ,a fIIe9.dgn
f ,lelO,dgn
t
My Compute,
, i filea. dgn
QI
. .
" I~
,I
li:4l
i:4l
,II -
Ii
My NetwOIk
Places
,I
Filename:
I
i
Save as Jllpe:
vi
[-MiclOStation
-------"-----"
.. _------:]
DGN Files ["dgnJ
,v ,
Save
Cancel
l
..I,
Ir
NOm)
441
If a file exists, the only way we are returned the file name and a return
value of 0 is if the user clicks "Yes" to over-write the existing file.
Entering additional file extensions in the File Filter parameter will
display the files associated with the entered extensions.
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
Ie Jrom'Seed":',(::\MlCrostation
VBA\: ,"W;f't.,<~W'4.i<'!:V
;~~':' ' ;,;:
'f' '/ ;-. ':',.;Ji'V-,
': '"
~' (reate
.. '''j} ~;. ", ~J,~
:iN """,,,~. "i~ ,,..,,4 ,..
(..---t..-'.~, \". ~ ~ H' 5,;"(~'I,W"',,<,'''~~
.. 't. ""l~}..A<"1\{~.f_'"t;'o\}M~,~ )".)11 ~.:t.",,~
"A
< j
Save in:
,
i
EJ Ii ei~~~f~]
i
I
[
Recent
; ICl cd material
rQ Source Code
D pics
t;.lll 0
~,
B' tm) T
~ lJ
~filea.dgn
~fileb.dgn
~rasterdocs.dgn
rQ docs
I ~filel.dgn
Desktop
v!J
My Documents
i ~ file2. dgn
! ~file3.dgn
I ~ file4 . dgn
! ~ fileS.dgn
~ file6.dgn
I ~ file7 . dgn
t ~ file8 .dgn
~file9. dgn
~ filelO . dgn
My Computer
f&l
i
I
Filename:
i
(
[
Save
Cancel
Browse
l
I
I
."
443
444
_.
I"formation
~~
<',~~
'"/1 '"
'70<
.,
~,
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
Class modules have a variety of purposes with these primary beneficial
uses:
IB To encapsulate similar functionality into a single object.
IB To create an object with properties, methods, and events.
IB To create class modules specifically for custom collections.
Each benefit will be the focus of a section in this chapter. The code we
write will target the use of the MicroStation Built-in dialog boxes and
other MicroStation-specific objects and functionality.
In this chapter:
IB Encapsulating similar functionality
IB Creating objects with properties, methods, and events
IB Using class modules with collections
445
446
[8
[8
[8
[8
[8
[8
[8
[8
[8
You have accomplished each of the desired tasks already in this book.
The focus of this exercise will be to wrap it all into a single class.
We want to display.dgn files, .xls files, and .txt files. We also want to
display multiple custom file extensions in the dialog box. We could have
an "OpenDGN" method, an "OpenXLS" method, an "OpenTXT"
method, and an "OpenCustom" method. The main difference between
these methods would be the file extension(s) supplied. So, instead of
creating new methods for each file type we may want to browse, we will
work with one method, named OpenOi a log, that handles any number of
file extensions.
Let's begin by working with the file extensions. There are usually
multiple ways to accomplish the same task when working with VBA. We
will use a dynamic array in our class to store the desired file extensions.
We need to allow the user (in this case, it is us as developers) to add file
extensions and clear the file extension list.
447
448
As we step through the code, you can see the effect of adding file
extensions by adding a watch to the variable MyUSD.
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 upperbound 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.
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.
Property Get ExtCount( ) As Long
ExtCount = UBound(pFileExts)
End Property
Now we are using true property code, because the property "ExtCount"
is based entirely on the number of file extensions we added to our class.
Specify the Read/Write capabilities of a property using Let and Get
statements. If you have a "Property Get" statement without an associated
"Property Let" statement, the property is read-only. If you have a
"Property Let" statement but do not supply an associated "Property Get"
statement, you are creating a write-only property. Write-only properties
are uncommon but can be used for storing confidential information
such as a password. You may want to be able to write to the property so
the class can use it but do not want to be able to read the property. And,
when you supply a "Property Get" as well as a "Property Let", you create
a read/write property.
Now get the file extensions with the "GetExts" property. This property
will be read-only, so use a "Property Get" statement.
Property Get GetExts() As Str in g()
If UBound(pFileExts) = 0 Then
Exit Property
En d If
Dim t mpGetExts() As String
ReOim tmpGetExts(UBound(pF ile Exts) - 1) As String
Dim I As Long
For I = 1 To UBound(pF i leExts)
tmpGetExts(I - 1) = pFileExts(I)
Next I
GetExts = tmpGetExts
End Property
450
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.
451
This is easy enough. Place the value stored in the variable pDefFilePath
into the property "DefaultPath". Let's take a look at the "Property Let"
statement now for the DefaultPath property.
Property Let DefaultPath(strPathln As String)
pDefFilePath = strPathln
End Property
Here is the Let statement. Take the value supplied to us and place it into
the Private variable pDefFilePath.
The Let and Get statements work just fine. Let's try it out. This next code
should be placed in a code module.
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
-~
>.
,-
,.
-"
-,
"'"
,-"
..
..'.~
, ~nd
Help
Sub TestFilePathB()
Di m MyUSD As New clsUStationDia l og
MyUSD.DefaultPath = "c : \test54321 "
End Sub
Now, even if the path "c:\test54321" does not exist, it is a path that could
be created because it meets the rules for drive letter and folder name. So,
even though we expect that we will feed our class legitimate paths, we
should handle error 52 just in case.
Property Let DefaultPath(strPathln As String)
On Error GoTo errhnd
If Di r(strPathln, vbD i rectory) <> "" Then
pDefFilePath = strPathln
End If
Exit Property
errhnd :
Select Case Err,Num ber
Case 52 ' Bad file name or number
Err.Clear
End Select
End Pr operty
453
Now, even if we supply an illegitimate path, the program will not crash.
Let's implement the "DefaultFileName" Property.
Property Get DefaultFile() As String
DefaultFile = pJefFileName
End Property
Property Let DefaultFile(strFileln As String)
pDefFileNa~e = strFileln
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 Functio n mdlDialog_fileOpen _
Lib "stdmd l bltin . dll " (ByVal fileName As String . _
ByVal rFileH As Long. ByVal _
resourceld As Long . ByVal suggestedFileName As String. _
ByVal filterString As String . ByVal defaultDirectory As String._
454
We discussed a great deal of code so far with this class. Let's take a look
at the code in its entirety just to make sure we haven't missed anything.
' General Declarations
Private Declare Function mdlDialog_fileOpen Lib "std mdlbltin . dll " (ByVal _
pFilePath As String
pFileName As String
pDefFi l ePath As String
pDefFileNa me As String
pFileNameSelected As String
pRetVal As Long
455
Private pF i leExts() As St r i ng
Property Get SelectedPath() As String
SelectedPath = pFilePatr
End Property
Property Get SelectedFile() As String
SelectedFile = pFileName
End Property
Property Get OpenSuccess() As Boolean
Select Case pRetVal
Case 1 ' Cancel
Open Success
Fa 1 se
Cas e
'Open
Open Success
True
End Select
End Property
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
' Open
Case
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
457
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
Each file extension added to the class displays in the FileOpen dialog
box.
ib
Lookjn:
EI
MicrosiaiionV8A
C l1r fjl
IT1].
C!J
;:Y"1
W
! ifO cd material
Recenl
HD source Code
I!g~::s
@ Ij~ file1.dgn
Desklop
l~ file3 .dgn
'",
!~ file4 . dgn
~ file8.dgn
~ file9.dgn
'
~;: :!~~~~n
~ fileb.dgn
~aa . dgn
~ rasterdocs .dg n
i l~ file5.dgn
f/jJ
M D
~ ,~ file6 . dgn
y ocumenls j~ file 7.dgn
I!m file7.dwg
l!
Ii' - - - - - - - - - - - - - - - -- - - - ---'
My Compuler
f Filename
~
., My
~.l.e.lwork
! Files of lI'pe:
i
ItmmI
~v:1
t~~~~::5!"'~~::.d~f ___________________________~_~J
Open .
:1
Cancel
Open as leadonly
In
the General
459
460
Once again, the only change using CreateDi alog instead of OpenDi alog.
Let's expand on Tes tShowDi a1ogA in a new procedure TestShowDi alog E.
Sub Test ShowDia log E()
Dim MyUSD As New clsUStationDialog
MyUSD . AddFileExt "dgn "
MyUSD.DefaultPath
"c: \ "
MyUSD . De f aultFile = "test.dg n"
MyUSD.OpenDialog
Select Case My USD.OpenSuccess
Case True
MsgBox "Open" & MyUSD.SelectedPat h &
MyUSD.SelectedFile
Case False
If MsgBox( "Create a new file? ", vbYesNo)
vbYes Then
My USD.CreateDialog
If MyUSD . OpenSuccess
Tr ue The n
Msg Bo x "Create " & MyUS D.Selecte dPath &
My USD.Se l ectedFi l e
End If
En d I f
461
End Select
End Sub
&emove ellsUStal:i6nDialoo.
~rint" .
. Doc!>;ble
tJide
462
Save in:
~.!:!!croslalion V8A
eiF~~t~:
e:l~d~~terial
!Q Source Code
IO docs
!Qpics
~__I~======-=_=_-=~~~J
File name:
Save as I~pe:
clsUSlalionDialog.cls
[Clas:.~~.:rcl~l._______. _ ~
Help
l.'ill()
File> Import .
!t:Jlcd material
1
Source Code
IC:l docs
110
'I!Q PiCS
@J!!iBM.lnJ.!J
!
File name:
Files of I~pe:
Open "
[ViiFi;;rh;;;~~--~-~
.'
I
[
Cancel
Help .
:.f
'J
463
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:
~~!~~'11?}2~:~~~~"'r"-:7'~~~~~F 7TP7-::~';7:~ ~~: < ""~~;~~~
A,c;: f,'" <,< y. 'F~' ': ,,'" :.ttM('{"
0"J.~1~.t.;;'.~../ .;""{~'vd~>]~''Y d~\, .fj>){:.% ~
'."'
Compile error;
Constants, fixed-length strings, arrays, user-defined types and Declare statements not allowed as Public members of object modules
OK
II
Help
464
10
10
10
Double
Double
Double
Point 3d
Point3d
465
St ar t Point.X ) / 2
StartPoint.Y) / 2
StartPo i nt . Z) / 2
10
10
10
Double
Double
Double
Point3d
Double
Double
Double
Point3d
Point3d
Double
Double
Double
466
Enough with properties. Let's look at creating methods. The first one
will be DrawLine.
Sub DrawL i ne()
Di m LineElem As LineE l ement
Set LineElem = Create Li neElement2(Nothing. _
pStartPoint . pEndPoint)
ActiveModelReference.AddElement LineElem
En d Sub
Set the Start and End Point values, then we use the DrawLine method.
That is simple enough. Try creating another method for our class
module.
This is a method named "DrawLinePerp". It draws a line perpendicular
to the one defined by the pStartPoint and pEnd Point properties of the
class through the midpoint of the line.
Sub OrawLinePerp ()
Dim PerpSt As Point3d
Dim PerpEn As Point3d
Dim PerpMid As Point3d
467
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
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
> ..
470
471
Long
String
msdLevelElementAcce ssAIl
MsdLevelElementAccess t
Long
Linest yleilineStyle
Long
Long
IsActive
Boolean
IsDisplayed
True
True
False
Boolean
IsFrozen
False
Boolean
IslnUse
False
IsLa eked
False
"Levell "
Boolean
Boolean
Name
Number
OverrideColor
1
0
Boolean
String
Long
Long
LinestylelLineStyle
OverrideLinestyle
OverrideLineWeight
Long
Parent Level
Nothing
Level
Plot
True
Boolean
UsingOverrideColor
USingOverrideLinestyle
True
True
Boolean
Boolean
UsingOverrideLineWeight
True
Boolean
~ em
Variant lObjectilevel
~em
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.
472
One way is to use the For Ea ch ... Next statement. The example above
populates a collection with the levels in the active model. Then you
access each object in the collection using For Each ... Next .
When objects are added to a collection, the properties, methods, and
events of the objects are live. That is they are not static variables holding
values. Be careful when accessing the objects that you do not modify
properties inadvertently.
Use For Ea ch ... Ne xt for easy access to each object in the collection.
Here is another way to access objects in a collection:
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 ( )
473
Now, instead of addressing the items from the top of the list down,
address the items from the bottom up by using a For ... Next statement
using "Step -1".
Let's take another look at the Collection Add method declaration:
Sub Add( Item , [Key]. [Before]. [After])
474
475
476
477
we draw a line between the entered X and Y values and the Start and
End Points of the myLineElem object.
Enter X Value:
OK
[ Cancel
Enter Y Value:
OK
I
I
I Cancel I
478
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
USING
479
480
End If
Next
End Sub
Five supported levels are specified. Join the array of level names
separated by tilde characters (- ). Then look in the joined string using
the InStr function. If the level is not found in the supported level name
string, print the level name to the Immediate Window.
Unsupported
Unsupported
Unsupported
Unsuppo rted
Unsuppo rted
Unsupported
Unsupported
Unsuppo r te d
Unsuppo rted
Unsuppo rt e d
<::F I
Level
Level
Level
Level
Le vel
Level
Level
Level
Level
Level
Fo und:
Found:
Found:
Fo und:
Fo und:
Found:
Found:
Fo und:
Fo und:
Fo und:
Level 1
Level 20
Level 23
Le vel 38
Level 39
Level 40
Level 41
Level 42
Leve l 47
Default
~.
~~l
XI
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
"ROADWAY "
GoodLevels(O)
Goo dLev el s(l)
"SIDEW ALK"
"PA I NT"
GoodLeve l s(2)
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
Leve lFound(I)
End If
Next I
0 Then
True
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
482
LevelFound(I)
End If
0 Then
True
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 )
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 FindUn su pportedLevel sC ( Fi l eToQuery As Design File )
Dim GoodLe vel s (O To 4) As String
Dim GoodLevelsJ As String
Dim my Level As Level
Dim FFile As Long
GoodLevels(O J
"ROADWAY"
"SI DEWALK"
GoodLevels(lJ
"PAINT"
GoodLevels(2)
Goo dLe vel s(3)
"ELE CT RI C"
GoodLevels(4)
"GAS "
GoodLeve l sJ = UCase( "- " & Join(GoodLevels . "- " J & "_ H)
FFile = FreeFile
Open "C: \MicroStation VBA\LevelsUnSupported . txt " For Append _
As #FFile
For Each myLevel In FileToOuery . Levels
If InStr( 1. GoodLevel sJ. " - " & UCase(myLevel . Name) & "- " )
0 Then
End If
Next
Close #FFile
End Sub
Sub Fi ndMi ss ingL e vel sC(F i le ToOu e ry As Des ignFi le)
484
Level Found( I)
End If
Next I
0 Then
True
Next
For I = LBound(GoodLevels) To UBound(GoodLevels)
If LevelFound(I) = False Then
Print #FFile. FileToQuery.Pat h & FileToQuery.Name &
vb Ta b & "MI SSING LEVEL: " & GoodLevels(I)
End If
Next I
Close /fFFile
End Sub
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
"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)
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
After this procedure is run, the design file meets the company's
standards for level names. We can work on the file with our customdeveloped VBA tools. Our designers and drafters do not need to refer to
"cheat-sheets" to remember which level name goes with which level
I Cross-Company Standards I
487
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
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
False
>
0 Then
Sp l it(txtIn , vbTab)
xSp 1 i t ( 1 )
1)
1)
Next
End Sub
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
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
Private Sub Class_Initialize()
Dim FFile As Long
FFile = FreeF i le
Open "C:\MicroStation VBA\TimeTrack.txt" For Append As #FFile
Print #FFile , "INIT " & vbTab & Now
Close #FFile
Set MSApp = Application
End Sub
Private Sub Class_Terminate()
Dim FFile As Long
FFile = FreeFile
Open "C: \M icroStation VBA\TimeTrack.txt " For Append As #FFile
Print #FFile, "TERM " & vbTab & Now
Close #FFile
492
Pr int #FFile . "REDR " & vb Tab & Now & vbTab &
Application.UserName & vbTab &
ActiveDes i gnFile.Name
Close #FFile
End If
End Sub
Private Sub IViewUpdateEvents_BeforeRedraw(TheViews() As View. _
TheModels() As ModelReference. _
ByVal DrawMode As MsdDrawingMode)
End Sub
Private Sub MSApp_OnDesignFileClosed(ByVal DesignFileName As Str i ng)
ITracking Time I
493
Cl ose #FFile
End Sub
Class_Te rminate
IViewUpdateEvents_AfterRedraw
OnDesign FileClosed
OnDesignFileOpened
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.
Sub TestTi meTrack ()
Set myME = New cls TimeTra ck
AddModelAc ti vat eEv ents Hand l er my ME
End Sub
494
Here is
the
output of
t he Class:
9/11/2005
9/11/2005
9/11/2005
9/11/2005
9/11/2 0 05
9/11/200 5
9/11/ 20 05
9/11/2005
9/11/20 05
9/11/20 05
9/11/200 5
3:08 : 13
3:08:17
3:08:19
3:08 : 20
3 : 08 : 23
3 : 08 : 24
3: 08 : 24
3:08:29
3: 08 :3 2
3:0 8 : 38
3 : 08 :5 2
PM
PM
PM
PM
PM
PM
PM
PM
PM
PM
PM
Admi ni s trator
Administrator
Administrator
Admini strator
Admi ni s t r ator
Admin i str ato r
Administrator
Administrat or
Admin is trat or
Admi nis trator
cogo.dgn
cogo . dgn
cogo. dgn
cogo . dg n
co ns t r aints . dgn
constrain ts. dgn
cons t rai nt s . dgn
co ns train t s.dgn
con s trai nts . dg n
co nst r ai nts.dg n
..
.:;
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.
-,~~j
~~""';''''''~;7,-A
~'?
",""~
,,,,::>;\~',(''''i~'';'r,'~.,~-
r~:
~.,-"
"'-~>_P",;;;-
',.,
r""l'<~'"
.~.,
,.'
v,,",
.lf8J
Name
I Description i Location
: Auto-Load
Sub OnProjectLoad ()
TestTimeTra ck
End Sub
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.
496
readonly
none
"""'~'y.:".v:n-"t"'''' -".~-"'_.::r:,,:~v-
::?":~~
.:: ."; . .
.,~
Cqf!figl!r!l~ton ~; lIJie,~ [!l!1titled]" " " ,,,,' " " ',' ,"
File
~"H~~~~V<"'"W""''''' ~~,.,
""~'
p,' '."
"
, , "
....
".>~~
,'.
. , '
AV
'
leis
- Development
~:~~~/l mages
~~~~i~es
IlI ing
~l' I [
II,
I f!e'~, ~
I I SelecL I
.
r~i
i.ii !
'1
Edit..
r,1 1Ewansion
i,dards Checker
'bOIOGY
:em Env
- - - - - - - - --- - - - - - - - - - - - - '
h'
Cancel
If
~'I:
'
:I
'ration
ling
,:~~i~:arch Paths
User
System
'!!
:1
gjl
t ~II
ill i
r Commands
(MS_VBANEWPROJECTD IR ECTORYJ
\_1, 1
;;1
~: !I
~i ~_~~~;~:_';';J l:!-
497
. . .0'
_,~_,.
~""<~"",
-_~_
~~
""
,.~
_''v~
_.
.~
,....
~.
...
'{:.
<
=:J
"~VO~ [ .,_
y_________.
~
~
___..--1
E:<pansion: readonl;-------------------P----------t
~."
,,<~
"'
_~~v_
.,,~~._
A~rt
.~N
_~'A
,
Save changes to your configuration file, [C:\Documents and
Settings\AII Users\Application
Data\Documents\Bentley\Workspace\users\untitled.ucf] ?
Click Yes to save the configuration file. Files marked as "ReadOnly" will
be opened in memory.
498
General
ICustom Ii Summary I
~
~
rr----------------------------J
~_~"!.'_ter2 :_~~~_~ ___________________ _
---_._----------_._--------Type of file:
MVBA File
Opens with:
Unknown application
Location:
Size:
Size on disk:
72 .0 KB (73,728 bytes)
Change .. .
---~===~
Created:
Modified:
Accessed:
---------------------Attributes:
[AI;!vanced ...
OK
I[
Cancel
Ii
8Ppl/
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
1
499
ettings\AU Us~rs~ppl!!=d!io~~
Project Properties.
~ Add-Ins
(t.
Help
f!.ddi\:onal Controls ..
[:1acros ...
Qptions...
Chapter2 1 Prop ~rties ... ~
General
Window
B.eferences...
[~~IfL_--_-----------
"*"" ,,0;;0",
r~-~~:~~~--------------------------lO
r~~~itiO.~ ~I_~~~.':il_~ t~o_~~r~~~=~~s_:_.___ _ ______
Project Help
W~:~I~----l
I
t
I
!
t
_._-_ . _ -------------_.._______1
~ .
OK
. :11
Cancel
I[
Help
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
~ Protection
1<--___________--,
<'
- - - - _._- - - - - - ,
~-----~--------~I I
!:assword
r'
..
OK
ij
I .Cancel II
Help
After saving the project, unload it and then reload it using the VBA
Project Manager.
When you get back into VBA after
loading your project, you see the
project in the project list with the
project tree compressed.
",--(-~t!>~
. . ~",
"
.~
!:assword
501
VBA PROJECTS
VBA projects are contained in a single .mvba file. This makes them easy
to distribute. Just e-mail a file to anyone in the world who has the same
version of MicroStation and they can use your program. Or can they?
From the VBA menu, select Tools> References to display the References
dialog box.
A portion of the
References dia log box:
/!vailable References:
El
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
flvailable References:
OK
Ali
Cancel
Browse".
i-.!J
Help
lIll!::~.:.~.~,:;.:~~~::}~J~r,::,,~"~,~,>,~~:,;..~,::J
,,~~l_i
6 11
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.
Why are these benefits? vVe can't run our code.
Because it is easy to write code that can damage MicroStation DGN files
and the Windows system as well. High Security Mode prevents unsigned
projects from being loaded and executed. Of course the next question is,
I Review I
503
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
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
[B
[B
[B
[B
50S
506
Here is the code in the OnDesignF i leOpened event. We write the date/
time and the file name to an ASCII Text file at
C:\MicroStation VBA \FileOpen.txt.
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 OnDesignFileClosed I
509
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?).
510
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
IISaveAsEvents Interface I
511
Now that the variables are declared, they can be used in the Aft er Remap
event as follows:
Private Sub ISaveAsEvents_After Rema p(
ByVa l TheDesignF il e As DesignFile . _
ByVal Sav ed Form at As MsdDes i gn Fi l e Format . _
ByVal Dest in ati onF il ena me As Str i ng)
Fi l eSaved = Desti nat i onF il ename
FileFormat = SavedFormat
FilePrevious = TheDesignFile .F ul l Name
End Sub
OK. We captured the DesignFile going into the SaveAs command as well
as the file format the file is going to be saved as, and the
DestinationFilename. What can we do with this?
In a previous example, we added design files to a zip file when the
design files were closed. This was a powerful example of the ease with
which great functionality can be implemented with only a few lines of
code in VBA (and of course, a little knowledge mixed in for good
measure). Can we top that functionality in the AfterSaveAs event?
512
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.
Sub CopyFileToCD (File ToCopy As String)
Dim myShell As New She l l
Dim cdFolder As Shel132.Folder3
Set cdFolder = myS hell.Nam pspace(59)
If Not cdFolder Is Nothing Then
cdFolder . CopyHere Fil eToCopy , 0
End If
End Sub
513
IISaveAsEvents Interface I
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
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
~..
_~~
~~v
~ OVO/CO-RW.Orive (0:)
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.
Private Sub ISaveAsEvents_A f te r SaveAs()
Se l ect Case Fi le For mat
Case msdDesig nFileFormatCurrent
Case msdDesignFileFormatDWG
CopyF i leToCD File Previous
Case msdDesignFileFormatDXF
Case msdDesignFileFormatUnknown
Case msdDesignFileFormatV7
Case msdDesignFileFormatV8
End Select
End Sub
514
! ISaveAsEvents Interface !
515
516
Thus far we have written a lot of code but we have been unable to run it
because the code is contained in a class module, so let's discuss how to
use the class module code.
You must call up the code in a class module by code in a code module or
UserForm. We will use a code module for this example.
Sub Te s tSaveAs ()
Dim mySaveAs As New clsSaveAs
AddSav eAsEven t sHandler mySaveAs
End Sub
I Review I
517
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
23
Responding to
MicroStation
Attachment Events
These next four chapters continue with responding to events in
MicroStation beginning with the IAttachmentEvents interface. Five
events are exposed.
In this chapter:
[B
[B
After Attach
[B
After Detach
[8 AttachmentModified
[8 BeforeAttach
[8 BeforeDetach
519
520
Two of the events refer to attaching a reference file and two refer to
detaching a reference file .
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
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
522
NewElement As Element)
[8 Property RevisionNumber As String
[8 Sub RewriteO
[8 Sub Rotate(Pivot As Point3d, AboutX As Double, AboutY _
As ElementEnumerator
[8 Sub SelectElement(Element As Element, [DisplayAsSelected _
As Boolean
= True])
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.
Private Sub IAttachmentEvents_AfterAttach(ByVal
TheAttachment As Attachment)
Dim TxtPt As Point3d
Txtpt. X = a
TxtPt . Y = -100
Dim RotMatrix As Matr i x3d
Dim myText As TextElement
Set myText = CreateTextElementl(Nothing. Now & n n &
TheAttachment.DesignFile.Path. TxtPt. RotMatr i x)
ActiveModelReference.AddElement myText
End Sub
Each time an attachment takes place, we are writing the path of the
attachment's DesignFile as text to the ActiveModelReference. As the
code stands now, the text will be added to the same place whether it is
I AfterAttach I
523
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.
Private Sub IAttachmentEvents_AfterAttach(ByVal
TheAttachment As Attachment)
Dim FFi le As Long
FFi l e = Fr eeF il e
Open "C: \MicroStatior VBA\AttachmentLog . txt " For Append As #FFi1e
Print #FFi l e . Now & vbTab & ActiveDesignFile . Path & vbTab &
TheAttachment.DesignFile.Path
Cl ose #FFile
End Sub
If you follow the code shown directly above, you see that we are writing
the ActiveDesignFile's Path and the attachment's path to an ASCII text
file named AttachmentLog.txt. You can use this log file to track file
dependencies.
One more example demonstrates additional use of the Attachment's
properties:
Private Sub IAttachmentEven t s_AfterAttach(ByVal _
TheAttachment As Attachment )
Di m PtA As Point3d
Dim PtB As Po i nt3d
Dim my Range As Ra nge3d
Dim MyRe c As Li neEleme nt
Dim Li nePts(O To 4) As Point3d
myR ange = TheA t tachme nt.Range ( True)
PtA = myRange . Hi gh
PtB = myRange.Low
LinePts(O).X
PtA . X: LinePts ( O) .Y
Pt A. Y
LinePts(l).X
PtB . X: LinePts(l) . Y PtA . Y
LinePts(2).X
PtB.X : LinePts ( 2).Y
PtB. Y
Lin ePts (3 ) . X PtA . X: LinePts (3) . Y PtB.Y
LinePts(4) . X PtA . X: Li nePts(4) . Y PtA . Y
Se t MyRe c = Applic ation . Crea teL ineEl ementl ( Not hi ng. LinePt s)
Act iveM od elReference. AddEleme nt MyRe c
End Sub
524
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.
Pr iv ate Sub IAtt achmen tE ven ts_Aft e rD eta ch( By Va l _
Th eA tta chm en t As Att ach ment )
Shell "c : \ Progr am File s\ Int e r ne t Ex pl or e r \ie xp lo r e .e xe " &
""" http : //www . trackmydgndra wi ngs.co m/log . asp ?f i le na me= " & _
Ac ti veDesignFi l e . Name & "&at t achment= " & _
Th eA t t ac hment . Des i gnF i le.Na me & """ ", vbMaximizedF ocus
End Sub
I AttachmentModified Event I
525
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.
Pr ivate Sub IAttachmentEvents AttachmentMod i fied (
ByVal TheAttachment As At t achme nt)
Debug.Print "A t tachme ntModified"
End Sub
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 )
526
IAt~achmentEvents_BeforeDetach(ByVal
TheAttachment As
Attach~ent)
In this example, we write to a log file. We capture the date and time, the
user who is detaching the file, and the full name of the file being
detached.
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
[B The BeforeActivate event
[B The ModelChange event
527
528
I Model Events I
529
530
Af te rAc ti va te :
Change :
Be fo reActiva t e:
Change:
AfterActivate:
Change:
f l angedval ve .dgn
fl angedval ve.dgn
f l ange dvalve . dgn
f l angedvalve.dgn
fl angedvalve .dgn
flangedvalve.dgn
flangedvalve.dgn
flangedvalve.dgn
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
Levels are so important to the organization of a design file that an
interface is provided just for Level events.
The ILevelChangeEvents interface exposes only one event which
handles these twelve types of changes:
[B
AfterChangeActive
[B
AfterCreate
[B
After Delete
[B
BeforeChangeActive
[B
BeforeDelete
[B
ChangeAttribute
[B
ChangeCode
[B
ChangeDisplay
[B
ChangeName
[B
ChangeName
[B
Change Parent
[B
TableRedo
[B
TableUndo
531
532
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.
I mp l ements ILevelC hangeEvents
'be fore change act i ve shows the ol d level name
Pr i vate Sub ILeve l Change Eve nts _L eve l Changed( _
ByVal Chan ge Type As Msd LevelChangeType , _
By Val TheLeve l As Level , _
ByVal TheModel As Mode l Ref erence)
I Level Events I
533
534
Case MsdLevelChangeType.msdLevelChangeAfterCreate
Case MsdLevelChangeType.msdLevelChangeAfterDelete
Case Ms dL evel Chan ge Type .m sd Level Cha nge Bef oreCha ngeA ct i ve
Now we are ready to populate our Select Case sLaLement to deal with the
Level changes. We cannot prohibit changes in this interface; we can only
react to the events.
Let's look at some useful events in this interface.
535
~sdLevelC~angeType.msdLevelChcngeAfterC~angeActive
This keeps a simple log of when the Active Level is changed recording
date/time, name of the level, name of the model, and the design file's full
name.
Knowing that a level was created is helpful. Knowing who created it can
be critical. This event is triggered after a level is created. A log file is
created/appended showing a Date/Time stamp, the user who created the
level and other miscellaneous information.
By the time this event is triggered, very little can be done with the level,
however we can still get its name.
536
The name of this event suggests that we are being told which level is
about to become active. Not so - we are being told which level is about
to become deactivated. We do not know which level is about to become
activated until the AfterChangeActive Event.
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
In this chapter:
[B
[B
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
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:
Ner.J Level (0)
Default 3
Default NelJ Level (0)
3
True
False
l:'.'~
i~
,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.
539
540
(0)
(1)
False
NeTJ Level
Default 3
(0)
(1)
3
False
False
.'' '1
-
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:
Pr i vat e Sub ICh angeT r ac kEv en t s_ El ement Changed(
By Val Af terC hange As El ement . _
ByVa l Be f or eC hange As Ele ment . _
ByVal Act i on As MsdChange Tr ackAct i on . _
CantB eUnd one As Boolean)
Selec t Case Appl i cation.CommandState.CommandName
Case "Delete Element "
Debug.Print "De l ete El ement "
Debug . Pri nt vbTab & BeforeChange. Le vel . Name & vbTab &
Act i on & vb Tab & CantBeUndone
Case Else
Debug.Print App l i cation.CommandState.CommandName
Debug. Pri nt vbTab & BeforeChange. Level. Name & vbTab &
AfterChange . Leve l . Name & vbTab &
Action & vbTab & CantBeUndone
End Select
End Su b
541
o
NelJ Level (0 )
Drag Select. i on
NelJ Level (0)
NelJ Level (0)
Element. Select.ion
Defau lt. Default 3
Fa l se
Delete Element
NelJ Level (0)
Fa l se
'I
Fa l se
False
<,
>
542
Example 1
Private Sub IChangeTrackEvents_ElementChanged(
ByVal AfterChange As El ement. _
ByVal BeforeChange As Element. _
ByVal Action As MsdChangeTrackAction.
CantBeUndone As Boolean)
Select Case Act i on
Case msdChangeTrackActionAdd
Case msdChangeTrackActionAppData
Case msdChangeTrackActionDelete
Case msdChangeTrackActionDrop
Case msdChangeTrackActionMark
Case msdChangeTrackActionMo de lAdd
Case msdChangeTrackActionModelDelete
Case msdChangeTrackActionModify
Select Case AfterChange.Type
Case MsdElementType.msdEle mentType TextNode. _
Ms dElementType.msdElementTypeText
If AfterChange.Level . Name <> "TEXT" Then
AfterChange . Level ~ _
Ac t i veDe s i 9 n Fi 1e . Le vel s ( .. TE XT" )
AfterChange.Rewr i te
End If
End Select
Case msdChangeTrackActionModify Fen ce
Case msdChangeTrackActionNewFilePositio nA ndModify
End Select
End Sub
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)
Select Case Action
Case msdChangeTrackActionAdd
Debug . Print "Add : " & AfterChange.Type & vbTab &
AfterC hange . ID. High & vb Tab &
AfterChange . ID.Low
Case msdChangeTrackActionAppData
Cas e msdC hange Tra ckActi onDe le t e
Case msdChangeTrackActionDrop
Case msdChangeTrackActionMark
Case msdChangeTrackActionModelAdd
Case msdChangeTrackActionModelDelete
Case msdChangeTrackActionModify
Case msdChangeTrackActionModifyFence
Case msdChangeTrackActionNewFilePositionAndModify
End Select
End Sub
Add :
Ad d:
Ad d:
15 0
6 0
'I
0
13 6
13 7
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.
Private Sub IChangeTrackEvents_E l ementChanged (
ByVal AfterChange As El ement . _
ByVal BeforeChange As El ement . _
ByVal Action As MsdChangeTrackAction .
CantBeUndone As Boolean)
Select Case Action
Case msdChangeTrackActionAdd
544
545
546
547
End Sele ct
End Func ti on
Add:
Add:
Add:
Add :
Add :
Add:
Add:
Add :
Add:
Add:
<
LineString
Line
0
Line
0
Line
0
Line
0
Curve 0
Shape 0
Ellipse
Ellipse
Text
0
0
139
140
141
142
1 43
144
145
0
146
0
147
148
-[
>:
Example 3
When
an
element
is
deleted,
'msdChangeTrackActionDelete'.
the
action
recorded
is
548
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.
Private Sub IChangeTrackEvents_ElementChanged(
ByVal AfterChange As Element. _
ByVal BeforeChange As Element. _
ByVal Action As MsdChangeTrackAction.
CantBeUndone As Boolean)
Dim my Level As Level
Dim LevelCount As Long
Select Case Action
Case ms dChange TrackAct i onAdd
Case msdChangeTrackActionAppData
Case msdChangeTrackActionDelete
Case msdChangeTrackActionDrop
Case msdChangeTrackActionMark
Case msdChange TrackActionModelAdd
Case msdChangeTrackAct i onModelDelete
Case msdChangeTrackActionModify
Case msdChangeTrackActionModifyFence
Case msdChangeTrackActionNewFilePositionAndModify
Select Case GetType(AfterChange . Type)
Case "Table"
Select Case CommandState.CommandName
Case "New Level "
LevelCount
ActiveDesignFile.Levels.Count
549
Se t myLev el = _
Ac t iv eDesign File .L ev els( Leve l Coun t - 1)
NelJ
NelJ
NelJ
NelJ
NelJ
NelJ
NelJ
Ne lJ
NelJ
NelJ
Level
Lev e l
Leve l
Level
Level
Level
Level
Level
Level
Level
Added.
Add ed.
Added .
Added.
Added.
Added.
Added.
(34) Added.
( 35) Added.
(35 ) Added.
(27)
(28 )
(29)
( 3 0)
(31 )
(32 )
(3 3 )
~ IY J
False Then
550
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
[8
[8
[8
[8
[8
551
552
EntnyNumber
[sin formation
Mslink
.. -
-........ -..........
..... -.-.. -.
.1-
553
Open the file ... \Examp /es\Civi/\Ogn \cogo.dgn. This file is installed
with MicroStation.
554
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.
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
' Sold Column
Set myCo lumn = New ADOX . Column
myColumn.Name = "S old "
myColumn.Type = adBoolean
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
' Acres Column
Set myColumn = New ADOX . Column
myColumn.Name = "Acres "
556
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
2.naps
'/jew Attributes
Q.uery Builder
Verify l,inkages
Ctrl+B
558
(,','" , ~
}~"
~"~'
. '"
,~,,~
!S;~~!IJ;5!, !!'~~~!~~~.s,e"
... ~~
':;V'..;,",
"'.,
'. , ..," J"
Cancel
I~O~L~ED~8;====='~1
Browse
"
~I
BUDBe Provider:
When you select New, a new UDL file is created and you are asked to
enter the UDL file parameters.
i
I
!
ProY-ider
ll~nnec~Advanced 11.6:11
Select the
~~~~~~ to_~~~:~~~.:. .
. .~E DB
want
I __._ ______ _
'"O;ml
________ ______
t
'll
!
f.. !
pro~lder~"~"~"~,.,,~~._,,._ _ _ _ l.~!
i~
:'.<l
r.21
OK
il l
Cancel
I[
q
:,
.1
,~
!::lext
i'
I.
Help
L---------..JIct1
2. Enter information to log on to the database:
User name:
P.o:o.'J,:,d:
o Blank password
559
The Connection tab gives
us the ability to provide
information regarding the
location of the database to
which we want to connect.
The interface in the
Connection tab changes
based on the selection in
the Provider tab.
560
~;;;i~-;;-VBA\D-;ta~~-;;;"db---I O
2. Enter information to log on to the database:
Pa'i','}v~!'Jd:
~===============~
L I_ _ __
o Blank password
_ _ __
_ _- - - '
~ . T~~i C:~~n~qij~n
I[
OK
Cancel
I[
Help
~"--'- 1
--- .: ".~","-"
tl)for~~~ion .
~'X.
'7"> "':
'~~.I "
. .' "
-<}~ ,,~
f."='
,..',
: P"~
possible.
To create an MSCATALOG table, go to
Settings- >Database->Setup.
;.
561
~.
"_,,
_ w_
~
_"'
"'"
Alert
There is no MSCATALOG table, Create one now?
this MessageBox:
Functions:
TaQ!es
i Value .9_1 _ __
_ ___ ~J
o Dataset Mode
o Execute Query on Open
o No Duplicate Rows
o Append to Dataset
Execute
Clear All
Clear Text
562
Clear 8)1
Clear Texl
oc_
~!t~ck~r\~!!7"~~' .';'~;'~!(',"f.0~'!.,,';1.j;l:;fJ~;:Z,g<' ~,
Expenses
Hislory!'-.
Lois 1'1)
mscalalog
vi
563
To display the History table in the Query Builder dialog box, doubleclicking on "History" in the list then click the Close button.
Select
1Where I '
r':
I Order8y I
History
mslink
Owner
PurchaseD ate
SoldD ate
0
~
I-
564
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:
256
a
1
True
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 & _
myLink . Islnformat i on & vbCr &
my Lin k . Ms 1ink
Next
End Sub
SQL
Thus far we successfully created a new database, added new tables to the
new database, and know how to attach DatabaseLinks to elements in
MicroStation. The only thing we are missing in our database is data! We
need to know how to add records to the database we created. You do this
566
Execute
Dear 811
------------------~
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.
'7' -*~<
>-""-~f1~""
Owner
I Jones Family
Sold
-:~-
'"
~~
" f@
Date Sold
Acres
Sale Amount
567
568
I Review I
569
If IsNulHmyRS( "SaleAmou nt " )) The n
txtSa l eAmount.Te xt
El se
txtSa'eAmount.Text
myRS("SaleAmount " )
End If
my RS.Cl os e
myDB.Close
Exit Sub
End If
myRS . Close
End I f
Next I
myDB.Close
End Sub
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
28
Tags
Tags store and display information associated with elements in a design
file and to display the same type of information from file to file. The
data stored in each tag is different. For example, "Drawn By" is a useful
piece of information for every file but the actual value may vary from
file to file.
Use the macros in this chapter with the "Building" project that is
installed with MicroStation.
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
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 Get Selec t edT agC()
Dim myTag As TagElemen t
Di m myEl emEnum As Elemen t Enumerator
Set myEl emEnu m = _
App l icat i on . ActiveMo del Reference . GetSelectedEle ments
While myElemEnu m. MoveNext
Se l ect Case myE l emEnum . Current . Type
Case MsdElementType.msdElementTypeTag
Set myTag = myElemEnum . Cu rr ent
If myTag Is Noth in g = Fa l se Then
MsgBox myTag . TagSetName & vbTab &
myTag . TagDef i nit i onName & vb Tab & myTag . Value
End If
End Se l ect
Wend
En d Sub
The TagSet tells us to which group a tag belongs. For example, does the
tag belong to a title block? Does it belong to a door schedule?
At this point we are getting some very useful information. If four tags
are selected, we see four MessageBoxes. If one tag is selected, we see one
MessageBox. Let's expand our code to include all tags that belong to the
same TagSet.
In the next example, we display tag information and use the selected tag,
but we display all tags that are siblings to the selected tag. We do this by
getting the all tags belonging to the selected tag's BaseElement.
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
575
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
577
Next
End Sub
This example opens each design file in the specified folder "for
program". This means the file is opened in memory but is not displayed
in MicroStation. You can open and manipulate files very quickly when
they are not rendered to the screen.
We are extracting one piece of information in this example that we have
not extracted before: the High and Low elements of the ID property.
Th is ID property is very important because it provides a unique
identifier for an element in MicroStation that persists from session to
session. So, storing the ID property of an element in a database, for
example, allows us to quickly and easily identify the element in
MicroStation hours, days, weeks, or months after we first worked with it.
578
When you have an ID, you can get its element by using the
GetEl ementBy I 0 procedure. After I set the tag's value based on the ID, I
rewrite the tag element. This procedure cannot be executed by itself. It
needs something else to call it. Let's look at a procedure that does that:
Sub TestChange TagA()
Dim myTag As Ta gEl ement
Di m myEnum As Ele me nt En umer ator
Set myEnum = ActiveModelReference.GetSelectedElements
While my Enum.M oveNext
Se l ect Case my Enum . Current.Type
Ca se Msd ElementType. msdE l ementType Tag
Change Tag myEn um. Cur rent .I D.High . _
my Enu m.Cur r en t. I D. Low . "ABC "
End Sel ect
Wend
En d Sub
In the real world, we store the High and Low elements of the ID
property in a database or in some other storage mechanism. In our
example, we get the ID property from selected elements, then use our
new procedure Change Tag to change the tag's value.
579
myFilter.ExcludeAllTypes
myFilter.IncludeType msdElementTypeTag
For Each myModelRef In myDGN.Models
Set myElemEnum = myModelRef . Scan(myFilter)
While myElemEnum.MoveNext
Set myTag = myElemEnum.Current
If StrC omp (myTa g.TagSe tN ame. TagSet) = 0 Then
If StrComp(myTag . TagDefinitionName . _
TagName) = 0 Then
myTag . Va l ue = NewVa l ue
myTag.Rewrite
End If
End If
Wend
Next
myDGN . Save
myDGN.Close
End Sub
In this procedure, I open the specified file "For Program", scan the file for
tags with a specific TagSet and TagName and set its value. Here's a
procedure that uses ChangeTag2 .
580
The above procedure changes each design file in the specified folder,
saves it, and gives all tags named "Checked By" in the TitleBlock TagSet
a value of "J Winters". Powerful? Yes. Dangerous? Potentially. Be careful
so that the programming you do benefits your employer instead of
derails your career.
Edit
Format
.' .
. :
" , ' :, : .. ~
"
,.'
rJ['QJ~
View Help
Ti t1 eel oek
Ti tl eBl oek
Ti t1 ee l oek
Ti tl eel ock
Ti tl eBl oek
T; tl eBl oek
Ti tl eel ock
Ti tl eel ock
Ti tl eBl ock
Ti tl eBl ock
Ti tl eBl ock
TitleBlock
(,!
Rev.
Job No
scal e
T; tl e
AE201
1.0
BS1300
1: 100
South El evat i on
~~:~~~d F~\'e
Ref
project File Ref
11568
0
11574
0
0
11569
11566
11567
0
0
0
11573
11576
11570
11572
11575
4] 12
0
~I
'th,!
;;"1
:2
4316
~l
) .
...
581
582
Writing to a text file is simple. Of course, an ASCII .txt file is useful for
reviewing in Notepad but isn't formatted. Let's modify the above
example and, instead of creating a .txt file, create an .htm file.
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> "
Set myDGN = Application.OpenDes i gnFile ForProgram (
583
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
File
Edit
View
Favorites
-~
Tools
Help
~ t~ ;
e ,~ ' ,y~ ~
El
iTag Name
iValue
Ic
rn"--High
='- - jJD Low
10------- ii1-568-------!
iTitleBlock
ITitl~Bi~~k
. . .. . .. .. . . .!D~t~
iID High
iID Low
10
i11573
- ;O-- - - j 11570
[0
TitleBlock
'~:;_~:Ol-=-=l-: ------------
;DRG NO.
'AE201
. "1i574.: I
. .----.. -.. ;1-1576'------- I
.....- ft>=:"
:-------..----.---.----.---~1-(;--------- ..--------1::;------------f;-~~.~.------- [
ifD~---------------
~ My Computer
v .
..
584
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
[B
WHAT IS
XML?
585
586
</parcel>
587
READING
XML FILES
There are several ways to read an XML file. You could use standard VBA
file Input/Output calls, reading each line of the XML file and parsing it,
but there is a better way.
Microsoft has given us some tools to work with XML files. The first step
is adding a reference to a Microsoft XML DLL file.
Available References:
OK
~I,'I
i [J ~licrosoft XML,
v2.6
v3.0
v4 .0
I[J Microsoft X~lL , vS.O
[J ~licrosoft X~lL, v6.0
Ilicrosoft X~lL, version 2.0
I' !cd ~licrosoft. Vsa.dll
; U ~licrosoft_JScript
.....,): Priority
![J ~licrosoft Vsa
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 .!
IW
Cancel
Browse ...
Help
I 1"" 1, ~'11MFlltil
! .~/
..;":!.!1
.>..1
C:\WINDOWS\5ystem32\inetsrv\w3ext.dll
Language:
Standard
588
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
589
In this example, I look at each record in the XML file and when I find
one with an mslink of 531, I print the record's fields to the Immediate
window. The code works to be sure, but it is not very efficient.
Let's look at this next example. Instead of looking at each and every
record in the XML file, I get only the mslink properties, look at them,
and then print each field in the Immediate window.
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
591
" &
myXField , Te xt
Next
Next
End Sub
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
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.
60 Pa~ce13 Found Bet~een 1 and 2 Ac~es.
10 CRESTlJOOD DEV HlC
86657
36 lJHlSTOH HAROLD J & JERRY H 46475
68 RODGERS CADILLAC IHC
61295
71 SAHFORO GEORGE B
58874
76 VISSER REAL ESTATE IHVESTIIEHTS 53599
87 J B F COHPANY & lJILBURS 63518
90 STEPHENS lJILLIA}! J & KATIlERINE NULLA}IE 44372
94 DA}IIEL REALTY CORP % EASLEY- HCCALEB &
5900 3
100 lJAL-fIART PROPERTIES INC 65364
107 KINGTON CURTIS H & PATRICIA 52386
110 lIURRAY TED E & HCKINNEY JA}IE S HI CHAEL
56333
111 ADKINS BOYD L & HARRHlGTml GLEHARO F
50360
113 HUGLEY DAVID B & PEGGY C % UNIOH SECURITY f!ORTGAGE
114 ADKDIS BOYD L & HARRIHGTON GLEHARO F
47912
139 CAIH LILLIE HAE LSD OHEGA E~rrpRS DIC
74120
144 CADI LILLIE l1AE 46608
1 49 CADI LILLIE lIAE LEASED lJE STS IDE IHC 50262
156 SCHUBERT f! A TR 69869
164 FIRST AlIERICA}1 NATIOHAL BANK
82497
184 CAHI LILLIE flAE LEASED OlIEGA ENTPRS HlC 5 9782
187 ROBERTS LARRY S & SUZAHNE
75045
44071
I~
0 lC3
rU~ ~~
"'""-<""
G; t91 (}
,~..
~I
4.~ 4~J"
..
,~,,,,,
""',
lo~ls ~ Qat~
~k~
,:" ~ I ~
l'lindow'
. ::/ I "1
.I.@,
... ~, . <.U( ~
~ ,lJ!b
,,",
,,~. $, _
('1
~
'"
.ZO
"
"rm'?
02
1
-- -,,'table Tension!
1200
2
l,7ico,lor
3 "r
Y":Eij ghtjft; ,
2
13 towers
4
TtN'
~OO ,_ '
5
1e""x+-IC""a:::-::b:-::
6
"I-I--.-::c=-:'::x:,,I-::-::-=:Yc'-I_ _ _~zJ..::1O""A'T7-=-:A:":SE,=,T,==-=,,I_ _Co..;ac::b-:o:
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=1841,?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
18610 21374
361 xy=18610.2137
18575 2151 2
741
16
18495 21363
259 xy~184 95,2136"
18460 21501
639
17
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 "
Set myWSheets = myXM L.getE l ementsBy TagName( "Worksheet " )
For Each my WSh ee t In my WSheets
Set myRows = myWSheet . se l ectNodes ( " . II Row " )
Fo r Each myRow I n myRows
Set my Ce l l s = myRo w. se l ect Nodes( " .IICell " )
For Eac h myCel l In myC e l l s
Debug. Pr i nt myCe ll . Tex t
Next
Next
Next
End Sub
Even though
XML
provides a
standard
mechanism
for storing
and
retrieving
information,
the structures
are different
fromformat
toformat.
You can read
theXMLfile
specification
in its entirety
at http://
www.w3.org/
XML.
595
Cable Tension
1200
17
color
weight/ft
2
13
tovrers
You see the values all right but how do you know which row and column
you are looking at when you get a value? To answer this question, you
must understand a little more about the Worksheet XML structure.
Each and every cell could have an ''Address'' property. This may be
convenient for us developers, but it would cause the size of the XML file
to increase. So, index properties are used when needed to identify where
a specific row or cell is located.
The first row in the worksheet has an attribute named "Index" that tells
the row number you are looking at. The first cell in each row also has an
attribute named "Index". The cell's index tells in which column the cell is
located. So, between the index of the row and the index of the cell, you
know exactly where the first cell in the first row is located.
The second cell in the first row is a different matter. If the first cell is in
column 2 and the second cell does not have an index attribute, the
second cell listed is in column 3. The next cell in the same row is in
column 4 if it does not have an index attribute. If the next cell has an
index attribute value of 8, it is located in column 8. Only use indexes on
the first cell and whenever a cell is not directly adjacent to another cell.
The second row works in a similar manner. If the second row in the
XML file has an index attribute, the row number is specified in the index
attribute. If an index attribute is not supplied, the row is directly below
the previous row.
A slight modification of the original code allows us to track the row and
column of the cell.
Sub ReadXMLFile2 ()
Dim myXML As New MSXML2.DOMDocument
596
Next
I Review I
597
Next
Next
End Sub
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
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
[B
[B
[B
[B
ASCII FILE
Edit
Format
View
Help
599
600
'-', '
'-'
-,'--'
'
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.
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.
" '-""" ~"
'.- , ....~
-~:
.,~,
"'
...
~;H'7>.3~~;"'"
''Y'''''~ f''
,'"
""'--
.""
Edit
Format
View
Help
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
" . _ .
",,-
~ 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
603
604
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))
605
Pick
!b ~licrostation VBA
[3 B j:I!iMi.f241hGi
[310 BatchA
A ,
BatchA\
Ii:;) BatchA-2
BatchA-3
10 BatchB
Ii:;) BatchC
!b BatchD
il
!b cd material
Ii:;) docs
Ii:::! Fonts
V '
OK
Cancel
606
C:\Microstation VBA\BatchProcessing
OK
t;J
Now, instead of asking the user to type in the root folder, the user selects
the folder. Each DGN file in the selected folder displays in the
Immediate window.
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
Sub ProcessFilesAndSubs (FolderIn As Scripting.Foloer)
Di m my Fil e As Sc rip t i ng .F ile
Di m mySubF ol der As Sc ripting. Fo l de r
For Ea c h my Fi 1e I n Fol de r In. Fi 1e s
Select Case UCase(Right(myFile . Name, 3))
Case "DGN"
Debug.Print myFile . Path
End Select
Next
For Each mySubFo l der In Fo l derIn.SubFolders
ProcessFilesAndSubs myS ubFo l de r
Ne xt
End Su b
Pro cessI nFol derE should look very familiar. We allow the user to select a
folder. After the folder is selected, we call the Process Fi 1esAndSubs
procedure using the variable myFolder to supply the Folderln
parameter.
Now we are inside Proce ssFi 1esAnd Subs . After declaring a couple of
variables, we examine each file in the FolderIn" folder. If the right three
characters of the file name are DGN, we print the file path to the
Immediate window (also called the Debug window). After we finish
looking at each of the files in the supplied folder, we begin looking at
each of the subfolders in the supplied Folder In" folder. For each
subfolder we find, we use it as the argument for the FolderIn"
parameter in Pr ocess Fi 1esAndSubs , the procedure we are already in. This
is what makes this procedure recursive. We are already in the procedure
608
Here is the
output of
thi s
Procedu re:
!' I
VBA\BatchP~ocessing\File
A. dgn
B. dgn
VBA\BatchProcess i ng\Fi l e C. dgn
VBA\BatchProcess i ng\Fil e D.dgn
VBA\ BatchP r oc ess ing\File E. dgn
VBA\B atchPro cess ing\B atchA \ Fil e F. dgn
VBA\ BatchProce ssing\ BatchA\ Fi l e G.dgn
VBA\ BatchP rocess i ng\BatchA\Fi le H.dgn
VBA\BatchProcessing\BatchA\File J.dgn
VBA\BatchProcessing\BatchA\BatchA- l\File
VBA\BatchPr oc essing\B at chA \ BatchA-l \ Fil e
VBA\BatchProcessing\BatchA\BatchA- 2\File
VBA\BatchProcessing\Bat chA\BatchA-2\File
-I
c: \Hinostation VBA\BatchP~ocessing\File
C : \Hic~ostation
C: \Hicrostati on
C: \ Hi cr ostation
c: \Hi c r ostati on
C:\Hi crostati on
C: \Hicrostati on
C:\Hicrostation
C:\Hicrostation
C: \ Hi cr ostati on
C: \Hicrostation
C:\Hicrostation
,~:
K.dgn
L. dgn
H.dgn
N.dgn
609
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.
File~
In Folder:
Files To Process:
GO
610
611
Dim I As Long
IsFileIn = False
For 1= 1 To ListToCheck.ListCount
If StrComp(ListToCheck.List(I
IsFileIn = True
Exit Functi on
End If
Next I
End Function
1). FilePath)
o Then
Dim I As Long
For 1=1 To Lis t BoxFr om .ListCoun t
If ListBoxFrom.Selected(I - 1) = True Then
If IsFi l eIn(ListBoxFrom. List(I - 1). ListBoxTo)
= False Then
ListBoxTo.AddItem ListBoxFr om. List (I - 1 )
El se
End If
End If
Next I
For I = ListBoxFrom.ListCount To 1 Step -1
If ListBoxFrom.Selected(I - 1)
True Then
ListB oxFrom .Re moveItem I - 1
End If
Next I
End Function
612
Files To Process:
Files In folder:
~tchPl'o)cessinQ
File A.,jO:ln
GO
A few items worthy of mention that may not be apparent at first glance:
[B
[B
[B
[B
[B
613
614
615
Now, each computer running this code has its own BatchProcess .log
file. We could base the log file on the "UserName" that is logged into the
computer but this could cause problems because we may log onto
multiple computers using the same "UserName" that has been
established specifically for batch processing. It is more likely that the
computer name on the network will be unique from machine to
machine rather than the user logged into each computer.
616
File
Help
~I
http://www.google.com/search?q=MicroStation
Google returns thousands upon thousands of pages related to
MicroStation.
617
this fictitious web site could log the file, the date/time, the IP Address,
etc. But we don't want the user to have to type in the URL every time a
file is processed. Right? Let's have our software send the request.
It is time for another Reference.
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
619
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.
2/20/2006
3/ 10/2006
4/24/2006
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.
C2GJ
Available References:
r~icrosoft
Browse .. .
Priority
Help
Locat ion:
C:\WINDOWS\systern32\cdosys.dll
Language :
Standard
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
TestEmail ()
Dim myMail As New CDO.Message
myMail.To = "batch@microstationlogging.com"
myMail.From
myM ai l.Co nfigu rat i on.Fi e l ds .It em( '' htt p : // s chemas . mic r osoft . co m/ '' & _
"cdo/configuration/smtpserverport " )
25
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
=
=
&_
"cdo/configuration/smtpserver " )
I Review I
621
" yoursmtpserver.com "
myMai l .Config ur ati on.Fi elds .lte m( "ht tp: // sch emas. mi cr osoft.c ami " & _
" cdo/con f igu r at i on/ sm tp ser ve rp ort " )
25
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
31
623
624
625
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
Standards Check A
The following code
clsStandCheckA.
is
placed
in
class
module
named
Option Explicit
Implements IStandardsChecker
Private Sub IStandardsChecker_AddedCheckerToStandardsCheckerApps( _
ByVal ApplicationXMLNode As Object)
Debug . Print "AddedCheckerToStandardsCheckerApps "
End Sub
Private Property Get IStandardsChecker_Ca l lForEachModel() As Boo l ean
Debug. Pri nt DCa 11 ForEachModel"
IStand ardsChecker_CallForEach Model = True
End Property
Private Sub IStandardsChecker_CreateSettings()
Debug.Print "CreateSett i ngs "
End Sub
Private Sub IS t andard sChecker_DeleteSet t i ng s ()
Debug.Print "DeleteSettings"
End Sub
Private Property Get ISta ndardsChecker_Description() As String
Debug . Print "D escription "
IStandardsChecker_Description = "VBA StandChk A Desc "
End Property
Private Property Get IStandardsChecker_DialogString() As String
Debug.Print "Dia l ogString "
I StandardsChecker_D i alogString = "VBA StandChk A Dial "
End Property
Private Sub IStandardsChecker_EditSettingsCByVal IsReadOnly As Boolean)
Debug.Print "EditSettings"
End Sub
627
Now we need to write some code that adds the above class module to the
Standards Checker in MicroStation. This code is located in a code
module.
Option Explicit
Private StandChk As clsStandCheckA
Sub AddChecker( )
628
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;
,~~
",>,>
>
~~
':-
.,,'"
>,>,' >
Settings ---.- - - -: : - - - -- - - -- -
,..
A><
';.v
"> i
- - -- -
:$~tii6d.~H~~:~ IW:OOldWP;;W;
Checks -'----------,,-,-----'---~.---
D
D
D
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.
The next dialog we see will vary based on the HasSettings property.
If we return a value of True in this property, we see a Settings
button.
4
After settings are made, we can select our new, custom Standards
Checker add-in.
',' ..<\' ~r$"~'S'''>'''-',,<' ''''ry~'
,.,
"~""'~iflJ:N.~"""
'!
",'-""
~?"<""""<J' ~
v-,.. "';::'''''' ,.
,,.:,
+<'" "',,
""""""'-""" "'~'l"""'W"'\..""""'~'"'Y~t-r"'~
,,"
:',,'
Settings ----,----,-
i~~ii;:69S.H~~~ I~W:~
r!1~Il;n~*~~.~ ~,v~a
DX
Checks - - - - - - - , - - - - - - - - - - - - - -----,-
D
D
D
D
D
Check Levels
Check Text Styles
Check Dimension Styles
Check Element Templates
Check Line Styles
OK
Cancel
629
630
,,~~'I'
,t~,~~,a~ds !=,~~c~er
Settings
:$:~~:;69iHi1.m:~
Se!tings
vi
Check.1>.
~j
Checks ~-----~-----------
631
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?
Cancel
632
Save the settings in the design file so settings are unique to each
design file.
We will examine one way we can save standards checker settings. Our
example here stores values in the Windows Registry. You can find
another method of storing standards checker (storing settings in XML
format in a .dgnlib file) settings in the MicroStation VBA Help file.
In this example we save our settings in the Windows Registry. Here is
the code behind the GUI:
Private Sub UserForm_Init ia l ize ()
chkLabelsWritten.Value =
GetSetting( "VBA Standards Checker ", "Settings", "Labels Written", _
False)
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 ", _
633
En d Sub
""
Then
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
634
635
636
637
638
Declare variables.
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.
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
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.
639
640
641
642
643
Next
End I f
End If
End Sub
So, we have added a few lines of code. What does this get us?
~
~.'
~ta"!.c!a~ds
After the
Standards
Checker is run,
we are shown:
....
,....
"
....,
' -..
,,~
Ch,eck ~omplete
>-c' ....
,._v ....'"
_~ ~
"~"
oProblems Fixed
64 Ignored Problem
Review Report File reportOI 2.xml?
~~ ' ,
'
.'
.:
"-",'
~3G1~;5$:&
StandardsChecked:
'.,
!;.
1.0.0.0
644
Now, when we view the report generated after the checker finishes, we
see the number of problems that were identified.
645
And if we expand the listing below the file name we see the specific
problems we added above.
~@~
fde
VIew
Favorites
Tools
Help
~BENrLEY
IQJ--Files Processed :
DExpand All
File Nome
,
.0
last
Form.t Author
Modified
nate
Problems
Remaining Ignore
Checked
.
2006103117 20D6f03124
C:lOocument nd SettingslAll U.erslApplicatlon .
O.t"Bentley\WorkSp.ce\ProJect.\Ex.mples\BulldlngI OgnIBSI3DOAE101 350kb OGNV8 Admln15trotor 23'45'22 14'00'52
PI.n.dgn
..
..
#
..i::~~.,
Sile
Model
Ground Floor Pl an
Stondard
V8AC heckA
V8ACheckA
V8AC he ckA
YBACheckA
V8ACheckA
4
'5
,6
.~
..:
V8ACheckA, ,
.liW!W
!Nt!
Him
64
Description
Room 111 is NOT in fil .
, Room 110 is NOT in fiI .
Room 109 is NOT in file.
J.
f Room
"
,'
.. -. -~~'....~:';~~',.~t.~~:~:,~:;:::~i;;;,;~~~:,,~ .,,~~\~,'
in fil . .
'"," "-.-. ~
' ~!
646
[cit
\\tw
r~
YeQs
~ :B..
9 M ::l 811
=-_......-..,- --'-~.=~
i_ ~"
GIO!Jn~
F!QQ( fJl~11
V8A ChcekA
<).o...>Jfl,,,il'l..
\i1),\Choclu\
:3
ClO!JflHloOll' Plan.
~OQn~'fl~Plall
_~
__=. _.
'
~O~1'Yl
."'. . . .::--'-----------~~-;;-'-""
Now, in addition to seeing problems that have not been fixed, we see
problems that have been fixed and those that have been ignored.
647
So, the OnP rojec tL oad procedure is the same for both autoload
mechanisms. What are the two mechanisms?
1
648
32
DECLARING
API CALLS
You can declare Windows API calls in the General Declarations area of a
code module. Once declared, use the API calls as you would use any
other function or procedure.
Here is an example:
649
650
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.
Public Declare Sub GetSystemInfo Lib "kerne132 " (lpSystemInfo _
As SYSTE~I_= NFO)
Pub li c Type SYSTEM_INFO
dwO em ID As Lon g
dwPageSize As Lo ng
lpM i ni mumApp li cationAddress As Long
lpMaximumApp l icati onAddress As Lo ng
dwActiveProcessorMask As Long
dwNu mberOfProcessors As Long
dwProcessorType As Lo ng
dwAl l ocationGranu l arity As Long
dwReserved As Long
En d Typ e
You will see examples of more types declared as we look at more API
examples.
UTILIZING
API CALLS
There are hundreds of API calls available for our use. Those presented
here are not in any particular order, nor are they necessarily related to
one another in any way. One call may deal with the logical drives on the
computer where the other may deal with screen resolution. In any case,
those listed here should be helpful.
652
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 .
Public Declare Function GetDrive Type Lib "kerne132" Alias
"GetDriveTypeA " (ByVal nDrive As String) As Long
Public Canst DRIVE_CDROM
653
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
Funct i on ReturnDriveType CDr i ve Let t er As Str i ng ) As St rin g
Di m l ngDriv eTy pe As Long
l ng Dr iv eTy pe = Ge t Dri ve Typ eC Dri veLett er)
Select Case l ng Dri veType
Ca se DRIVCCDRO M
Retu r nDr i ve Type
"CD / DVD Dr i ve "
Case DRI VCF I XED
"Ha r d Dr i ve "
ReturnD r i veType
Case DRIVE_RAMDISK
"RAM Disk"
ReturnDriveType
Case DRIVE_REMOTE
"Mapped Drive"
ReturnDriveType
Case DRIVE_REMOVABLE
"Removable Drive "
ReturnDriveType
Case Else
lngDriveType
ReturnDriveType
End Select
End Function
Dr ive
Dr ive
Drive
Drive
C:\
D: \
E: \
Z: \
is
is
is
is
a
a
a
a
Hard Dr i ve
CD/ DVD Drive
Removab l e Dr i ve
Happed Drive
>;
654
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
GetVersionEx
What operating system is the computer running? We need only ask
GetVersionEx to find out.
Public Declare Funct i on GetVersionEx Li b "k erne 132 " Alias
"GetVersionExA" (lpVersionInformation As OSVERSIONINFO) _
As Long
Public Type OSVERSIONINFO
dwOSVersionInfoSize As Long
dwMajorVersion As Long
dwMinorVersion As Long
dwBui l dNumber As Lo ng
dwPlatformId As Long
szCSDVersion As String * 128
End Type
Public Const VER PLATFORM WIN32 WINDOWS
Public Const VER_PLATFORM_WIN32_NT = 2
655
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
number and service pack.
656
Sleep
At times, we need to temporarily pause program execution. The Sleep
func tion allows us to specify how many milliseconds to sleep.
Public Declare Sub Sle ep Lib "kerne132 " (ByVal _
dwMi lli seconds As Long)
OK,
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.
Public Declare Function FindExecutable Lib "shel132.dll "
Alias "FindExecutab l eA"
(ByVal lpFile As String, ByVal lpDirectory As String, _
ByVal lpResult As String) As Long
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
657
1)
GetDiskFreeSpace
GetDiskFreeSpace gives us information about the provided disk name.
Public Declare Function GetDiskFreeSpace Lib "k erne132 " Alias
"GetDiskFreeSpaceA " _
(ByVal lpRootPathName As String, lpSectorsPerCluster As Long, _
658
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.
Publ ic Declare Functian GetSystemMetrics Lib "user 32 "
(ByVal nIndex As Long) As Lang
Public
Public
Public
Public
Pub li c
Pub li c
Public
Public
Public
Public
Public
Public
Public
Pub lic
Public
Public
Public
Public
Public
Public
Public
Public
Public
Public
Public
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
Canst
SM CMETRICS = 44
SM CMOUSEBUTTONS
43
SM_CXBORDER = 5
SM_CXCURSOR = 13
SM_CXDLGFRAME = 7
SM CXDOUBLECLK = 36
SM CXFIXEDFRAME
SM CXDLGFRAME
SM_CXFRAME = 32
SM_CXFU LLSCREEN
16
SM_CXHSCROLL = 21
SM_CXHTHUMB = 10
SM_CXICON = 11
SM_CXICONSPACING
38
SM_CXMIN = 28
SM CXMINTRACK
34
SM_CXSCREEN = 0
SM_CXSIZE = 30
SM_CXSIZEFRAME = SM_CXFRAME
SM_CXVSCROLL = 2
SM_CYBORDER = 6
SM_CYCAPTION = 4
SM_CYCURSOR = 14
SM_CYDLGFRAME = 8
SM_CYDOUBLECLK = 37
SM CYFIXEDFRAME
SM CYDLGFRAME
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
659
SM_CYFRAME = 33
SM CYFULLSCREEN
17
SM_CYHSCROLL = 3
S~I_CY :CON = 12
SM CYICONSPAClt'-iG
39
SM_CYMENU = 15
SM CYKANJIWINDOW
18
SM_CYMINTRACK = 35
SM_CYMIN = 29
SM_CYSCREEN = 1
SM_CYSIZE = 31
SM_CYSIZEFRAME = SM_CYFRAME
SM_CYVSCROLL = 20
SM_CYVTHUMB = 9
SM_DBCSENAB LED = 42
SM_D EBUG = 22
SM MENUDROPAL IGN MEN T 40
SM_MOUSEPRESEN T = 19
SM_S WAPBUTTON = 23
GetTickCount
How long has it been since the computer was started? GetTickCount
answers this question in milliseconds.
Public Declare Function GetTickCount Lib "kerne 132" Alias
"GetTickCount " () As Long
4458484
4460484
OK
Sub TestTickCount ()
Dim StartTicks As Long
Dim EndTick s As Long
StartTicks = GetTickCount
660
GetUserName
Who is logged onto the computer?
Public Declare Function GetUserName Lib "advapi32.dll" Alias_
"GetUserNameA" (ByVal lpBuffer As String. nSize As Long) As Long
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.
GetWindowsDirectory
Where is Windows Installed? C:\Winnt? C:\Windows?
GetWindowsDirectory tells us.
Public Declare Function GetWindowsDirectory Lib
"kerneI32 " Alias
"GetWindowsDirectoryA " (ByVal lpBuffer As String, _
ByVal nSize As Long) As Long
Sub TestWindowsDir()
Dim WindowsDir As String
661
r )
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
662
End Se le ct
End Sub
This example uses an InputBox for entering the password. Although this
is not necessarily the best way to ask for a password (because it is visible
to anyone looking over one's shoulder), the code still demonstrates the
API call. We have a function named Cur ren tU ser Name that returns the
current user name. Notice that we leave the domain an empty string. If
we were on a domain, we would specify it in the provided parameter.
LogonUser. Very powerful.
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.
Pub l ic De clare Funct i on Mess ag eBeep Li b "us e r3Z "
(ByVal wType As Long) As Long
Pub l ic
Publi c
Public
Public
Public
Const
Const
Const
Const
Const
MB OK = &HO&
MB_ ICONS TOP = &H1 0&
MB_ICO NQU ESTI ON = &HZO&
MB_ICONEXC LAMATION = &H30&
MB_ ICO NAS TER IS K = &H40&
Sub TestMessageBeep ()
Message Beep MB_OK
Sleep 500
MessageBeep MB_ ICONSTOP
Sleep 500
MessageBeep MB_ ICONQUESTION
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
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 TestPlaySou ndB ()
Pl aySound "C: \W i ndows\Media\chimes .wav " ,
Sleep 150
Pl aySo und "C: \ Win dows\ Med i a\ch ime s . wav " ,
Sleep 200
Pl aySound "C: \ Wi ndows\ Media\chi mes.wav " ,
Sleep 250
PlaySound "C:\Windows\Med i a\ch i mes . wav ",
Sl eep 300
PlaySound "C: \ Windows\Media\chimes.wav " ,
End Sub
0 , SND_ASYNC
0, SND_ASYNC
0 , SND_ASYNC
0 , SND_ASYNC
0 , SND_ASYNC
When we use the "SND _ASYNC" flag, the specified file begins playing
and the code continues executing without waiting for the file to finish
playing. By placing sleep calls between each line of code, we hear 150
664
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.
Public Declare Function ShellExecute Lib "she l 132.dll" Alias
"ShellExecuteA" (ByVal hwnd As Long, _
ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpPa rameters As String, ByVal lpOirectory As String, _
ByVal nShowCmd As Long) As Long
Sub TestShellExecuteA()
ShellExecute 0 , "OPEN", _
"C: \Windows", vbMinimizedNoFocus
"Greenstone.bmp " ,
End Sub
Sub Te stS hell ExecuteB ()
Shell Execute 0, "OPEN", _
"Greenstone.bmp ",
"C:\Windows", vbMaximizedFocus
665
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.
Public Type SHFILEINFO
hlcon As Long
ilcon As Long
dwAttributes As Long
szDisplayName As String * 255
szTypeName As String * 80
End Type
Pub 1i c
Publ i c
Publ i c
Public
Publ i c
Pub 1i c
Pub 1i c
Public
Public
Pub 1i c
Pub 1i c
Pub lic
Pub l i c
Publ i c
Publ i c
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
Const
SHGFI_ATTRIBUTES = &H800
SHGFI - EXETYPE = &H2000
SHGFI - DISPLAYNAME = &H200
SHGFI - ICON = &HIOO
SHGFI - ICONLOCATION = &HIOOO
SHGFI - LARGEICON = &HO
SHGFI - LINKOVERLAY = &H8000
SHGFI_OPENICON = &H2
SHGFI - PIDL = &H8
SHGFI - SELECTED = &HIOOOO
SHGFI - SHELL ICONSI ZE = &H4
SHGFI - SMALLICON = &Hl
SHGFI - SYSICONINDEX = &H4000
SHGFI_TYPENAME = &H400
SHGFI - USEFILEATTRIBUTES = &HIO
Sub TestGetFilelnfo()
Dim myFI As SHFILEINFO
666
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
667
668
Controls.
TooJboH"J~~' .. ~:~
Contlols
<
Delete ItJ:f
Customize Item
e,vailable Contlols:
1
'0 Miclosoft Help 2.0 Contents Control
Cancel
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.
669
SUIl
Mon
1
30
Tu e
Wed
Thu
Fri
Sat
10
11
-12
13
14
-15
16
17
18
19
20
21
22
23
24
2S
26
27
28
29
30
-'
13
:3
10
For
demonstration
purposes, I will use the
"Calendar Control 11.0"
control in this example.
This control is installed
with Microsoft Office.
Select it from the list of
Available Controls and
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.
Pr i vate Sub bt nDi s play Select i on _Cl i ck()
MsgBox Calendar l .Va l ue
End Sub
670
(;t)
USING EXISTING
DLLs
There are two fundamental ways to use DLLs in our programming. Each
method has been used in this book already.
Method 1: Declaring DLL Functions as in the Windows API chapter.
Method 2: Adding a reference to the D LL and using it.
Since we have already devoted a chapter to using the Windows API, we
will turn our attention to adding references.
We have added references to a number of different DLLs but have done
so in the interest of discussing specific topics. Now, we are going to look
at a number of references in greater detail.
Let's first look at the "Microsoft Shell Controls and Automation"
reference.
671
Classes
Q <globals>
@I DF Constraint
@j DSheliFoldeNiewEvents
@I Fold er
@I Fold er2
@I Folder3
@I
@I Folde rltems
@I Folde rltems2
@I Folderltem s3
~ Fo lderltemVe rb
~ Fold erlte mVerbs
@I lNeVINIIDEvents
@j IPasspo rtCli entSe rvices
@I lSea rchComman dExt
Class
Member
r:Jj
'1
!t: /1J
~ :i "'~ InvokeVe rb
UJ '!'
@'I
r1jI
@i'
r1jI
IsFol der
IsLink
ModifyDa te
Name
Parent
Path
Size
Type
" "~Ve rb s
,~
Clas s Folderltem
Member of Shell32
Oefinrtion of interface Foldernern
672
,'"'
'"
~,,,,..,.
~~~-
~ ,~'
,-.
..
El
fO
Bentley
ID Documentation
ID Licensing
El
C)!IiMto
til
assemblies
tillD config
ID docs
til ID featuremodeling
ID icons
til
mdl
til
to
~i
.!~,
[ Make New Folder
OK
~ l,,-_c_a_nc_el~
Browse
fQ
673
Documentation
iii
~licroStation
Here are a few more examples. They are all harmless, even the
ShutdownW i ndows call. When you use ShutdownWi ndow s, you should be
prompted as to what you want to do. Simply click Cancel and everything
will be OK. It is a good idea to save open documents before using this
call, just to be safe.
Sub TestShellC ()
Dim myS he11 As New Shel132 . She 11
myShe1 1.Fi ndComputer
En d Su b
Sub Tes t She ll D()
Dim myShe11 As New Shel132.She11
myShe 11 . ShutdownWi ndows
End Sub
Sub TestShel l E()
Dim myShe11 As New She l1 32 . She11
myShell.Open "C; \Program Fi 1e s\Bent1ey"
End Sub
674
Back
[~ I jJ Search [e~
Folders i
[ill].
ro
IiiJ
",c' IClMicroStation
File Folder
File Folder
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
675
C:\Program
C:\Pr ogram
C:\Program
C:\Program
c: \ Program
c: \ Program
c: \ Program
c: \ Program
C:\Pr ogram
c: \ Program
C: \ Program
c: \ hogram
C:\Program
C:\hogram
c: \ Program
C: \Program
Files\Bentley\Documentation
Files\Bentley\Licensing
Files\Bentley\HicroStation
Files\Bentley\HicroStation\assemblies
Files\Bentley\HicroStation \ assemblies\ECFrame1>Jork
Files\Bentley\ lhcroStat ion\ assemblies\ECFrame1>Jork \ extensions
Files\Bentley\ lhcroStation\ assemblie3\JSpace
File 3\Bentley\lhcroS tation\ a33emblie3 \ JSpace \AddIn3
Files\Bentley\HicroStation\as,emblie3\JSpace\managed
Files\Bentley\ lhcroS t ation\ aS3emblies\JSpace \ resource
Files\Bentley\HicroStation\a33emblies\JSpace\unmanaged
Files\Bentley\HicroStation\ config
File,\Bentley\HicroStation\config\appl
Files\Bentley\HicroStation\config\database
File3\Bentley\lhcroStation\ config\ system
Files\Bentley\HicroStation\docs
676
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.
Sub Tes t FSOD()
Dim myFSO As New Scripting.FileSystemObject
Dim myFile As Scripting . File
Dim myTS As Scripting.TextStream
Dim strWhole Fi le As String
Dim xSplit As Variant
Set myFile = myFSO .G etFi l e(
"C: \Program Files\Bentley\MicroStation\config\msconfig.cfg")
677
Ex ressron
Value
T e
Come~
Ir.M~~x!mIl"III<ElxPlrelslsiolnlnmldlelfinledlinlclomlel~1>1I1I1I~Elm~IYIiIm~miIiMomd~u'
eI1~.Te!~~Fs~o~DIIIIIII~
lro'l'
,I..
e- xSpl~(O)
"#------------------------------------------------------------ SIring
Module1 .T e~FSOD
e- xSpl~(1)
"#"
SIring
Module1.TestFSOD
II-
ee-
xSpl~(4)
xSpl~(S)
xSpl~(2)
xSpl~(3)
SIring
Module1.TestFSOD
Module1.Te~FSOD
Module1
Module1
.Te~FSOD
.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
,~ ~;~~s~,:~~e!,,~pll!,r~J~~~~~~ ,
! File Edit View Favorites Tools Help
C Back
. :............. ...............
j
~ ~
". ... .. . . .. . .
LAddres~ I~ C:\test.htm
2
@l Done
til lf J search.... , .. .
. ......., ....1.....
!Candice
Ii, I 1. .~ My Computer
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
Sub RecursiveFolder(FolderIn As Scripting.Folder. _
DictionaryIn As Scripting.Dictionary)
Dim myFile As Scripting.File
Dim mySubDir As Scripting. Folder
For Each myFile In Folder In .Files
If UCase(R ight(my File .Name . 4))
" . CHM" Then
Dictionaryln.Add myFile.Name. myFile.Path
End If
Next
For Each mySubDir In FolderIn.SubFolders
679
Ii
680
Sending e-mail using VBA is easy. It takes a few lines of code because
there are a some settings you need to make. Once the settings are in
place, the e-mail is sent.
From:
myaddress@myserver .com
To:
youraddresS@yourserver.com
Cc:
Subject:
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
681
tlelp
myaddress@myserver,com
To:
Cc:
Subject:
youraddress@yourserver.com
K)
(~)
VBA
II For
MicroStation
682
General
S-um-;';ary
I Statistics 1
Design Properties
Tille:
If=
========~
Subject:
;::L=========
Client:
f=1
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.
Bentley'Systems, Inc.
Sub TestDSOA ()
Dim myDSO As New DSOFile . OleDocumentProperties
myDSO .Op en "C:\ test . dgn " , True
MsgBox myDSO . SummaryP rope rties.Author
myDSO . Close
End Sub
683
End Sub
I::~:, ~~~~;~
Author:
Category:
I~'licro5tation
Keywords: I'VSA
__
liSA
_ __ _ _
--~~__-_ .
I
_-_---ll
Comments :
Advanced
684
685
TestDSOD looks very much like TestDS OA, only we are opening a differe nt
Title:
~'--s-am-pl-e,-tx-t f-ile- - - - - - - - - - - - - - - - - , i I
~------~
Subject:
~ation VBA
Author:
I'
Category: [ dsofile
~._.~
~' I
-
" I
- - - - - - - - - - - -_ _ _ ~-_I
Advanced> >
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
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
687
! General
Custom
~~U-
_ _ _ _ _ _ _ _ _ _ _ _ _ _- ,
v ,i
Name:
Type:
!Text
Value:
r----------------------------J
vi
!. ......- .. ~- ..----.-----.---..---.---.-------j
Properties:
Name
Value
Type
Text
),-,
1_ _ OK
,II
Cancel
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
34
CONNECTING TO EXCEL
There are three ways to 'connect' to Excel. We will begin by using
"GetO bj ect".
GetObject
Sub TestExce l A()
689
690
End Sub
If Excel is not
running, we see
an error when
we attempt to
'get' Exce l.
"''Pm'' ;\"e!:;$!l " .... '" .'!'-;:-W~;"." '" ' '" - -"' .'
"'P_~ -.,.-
("t
.1
Y.
,~
.-
..
""'"\'.""''-;'"
",'
K~ ,,~
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.",
__:'
:;g,
;~L..
_..
~
~
Browse".
TestExcelB ()
Dim my Ex c e 1 As Ex c e 1 . APP1 i cat ion
Set my Ex eel
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~
....... . .... .. . . .... . .. . ............................
!~
@' ActiveChart
@i' ActivePrinter
@' ActiveSheet
@i' ActiveWindow
@' ActiveWorkbook
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.
Sub
TestExcel D()
Di m my Ex eel As Ex eel . APP1 i c at i on
Set my Excel
my Ex eel . Vi s i b 1e = T ru e
myE xcel . Wor kbook s . Add
End Sub
692
TestExcelD2 ()
Dim myExcel As New Excel.Application
my Ex c e 1 . Vis i b 1 e
True
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
693
50
500
1000
1500
2000
2500
3000
60
600
1200
1800
2400
3000
3600
v,
>U
694
20
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 " )
Set mySheetA = myExcel .Acti ve Workbook .W orks he ets( "Si mpl eGr id" )
MsgBo x myShee tA . Range (" B1") . Text
End Sub
E~~~-=--=--=~
_____-=-___ _____==_=--==~=--===---=--=--=:=~~~~~=~~=
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
695
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
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
697
counting out 'AP.:.', 'A B", 'AC" to fi nd out what the Colum n Index is of
Column "DC".
Settings
~~i~:~~:tt:;n:::IE!t!on$
~ Function tooltips
OK
I[
Cancel
698
1 To 7
For CurCo l
1 To 6
TestExcel M()
Dim myExcel As Excel.App l icat i on
Dim my Se 1e c t ion As Ex c e 1 . Ran ge
Set myExce l
Set my Se 1e c t i on
my Ex c e 1 . Se 1e c t ion
In this example, the selection was "B2" through "B7" (2,2 to 7,2).
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.
Sub TestExcel N()
Di m my Exce l As Exce l . App l i cation
Dim mySelection As Excel. Range
Dim myS heet As Exce l . Worksheet
Dim StartRow As Long: Dim St a rtCol As Long
Dim End Row As Lo ng : Di m EndCo l As Long
Dim X As Long: Dim Y As Long
Dim XSplitA As Varia nt: Dim XSp li tB As Va ri ant: Dim XSplitC As Variant
Set myExcel
Set my Se 1 e c t ion
Set mySheet
my Ex c e 1 . Se 1 e c t ion
my Exce l. ActiveSheet
XSplitC
StartRow
Sta rtCol
XSpl i tB(l)
700
" R",
"" )
XSp 1itC(1 )
For Y = StartRow
For X
~o
EndRow
StartCo1 To EndCo1
Get 0 b j e c t (,
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 TestExcel O()
Di m my Ex c e 1 As Ex c e 1 . APP1 i cat i on
Dim my Se 1e c t ion As Ex c e 1 . Ran g e
Di m myCe 11 As Range
Dim strAdd As Str in g
701
(2,2)
(2,3)
(2,4)
(3 ,2 )
(3,3 )
200
300
400
400
600
<,)
We need to remember that when we are dealing with Excel, we are
looking at (Row, Col). The Row comes first. When we are accustomed to
dealing with (X, Y) this can take a little getting used to because Excel
thinks in terms of (Y, X).
So far we have done a lot of 'pulling' from Excel. Let's try doing a little
'pushing' now. We are going to change a cell's value, a cell's formula, and
then perform a Copy and Paste operation.
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
"Degrees "
"Ra dians "
xlCen t e r
xl Ce nte r
xlCenter
703
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
704
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.
705
Now that we have seen the formulas, let's take a look at the values
generated.
A
BC
1
X
Y
Z
2
-2208716598"
33.06775051
10.80048308
3
-6.328729698
-33.55681358
-15.12641372
4
34.56159917
-10.503424
6.740530447
-4 .622206053
2807424377
11.58952008
5
6
-29.87002472
-42.94468857
-1803490077
7
41.69913054
-25.40802339
17.79778593
0.302771807
-12.71775582
8
18.51114764
-43.30360124
-4.219122549
17.52240842
9
10
27.57192593
36.50908479
-5.833780353
11
27.82085713
-1.916510652
16.59443405
... . .................
12
47.68307758
22. 11381557
-8.423401139
13
-49.79771456'
;)O-.S208630g:fo97469319
. -- ._._. __.__._._.'"
-_._-----_.._-_.--_. '
14
-28.44507751
11 .91563398
23.67553777
15.35135842'- -'-7~715i8G75 ---2246271813
15
16
1621397367
f4071189ii ':5470716498'
17 .... ~94??~3~_~~.
4561203874 '
16S.74~187 ;
18
-36.0 12428862427163771 ' -5.996325708
19
3443S15521: ' 14 51513287; :12j1695913' .
20 . . ... ':25.498429 i 9' . ..... 1:2 18440165 ' . ........ ... :46610566 ; '
21:1.344~9S2 l -3963885911'
-1434005614 "
22
-4035505243': 15:5432170i
-7.858884602'
23
-1846141973 , .3S73125351 1 " :19.68034631 '
24 .. . 37294 10466' :33s'47663-75 -1124281S18 '
25
-6.704128391"- :1S.2653331' :2967s7557,
26 -.-----.-1.553724653'-2912092628
4542'2'73424 '
.. "1
..- ...----.. - ..- .., . _._-_ .. _-- .- -....-. -t---------------- --';'
1
2
3
2
1
2
3
2
1
2
3
2
1
2
3
2
l'
. 2 '"
3'
2
1
2
3
2
. . - 1'
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
Set my Ex c e 1
<> ""
" &
" &
myWSA.Cells(CurRow, 3 )
CurRow
CurRow + 1
Wend
myWSA . Calculate
End Sub
706
Our Worksheet has a column for "Level". In the above example we are
not making use of it. Let's build upon TestExce l U now and place the
TextNode on a specific Level.
If we attempt to place an Element on a Level that does not exist, we will
get an error. Let's create a new Function named CheckLeve 1 that creates a
Level if it does not exist. We will use this Function inside Tes tE xce 1V.
Fun ct i on Chec kL eve 1 ( Le ve 1 Na me As St r i ng) As Leve 1
On Err or Res ume Next
Set Chec kLeve l = Act i veDes i gn Fi 1 e . Level s ( Level Name)
ITag Extraction I
707
Notice how the Function Check Leve 1 returns a Level Object. We use this
Level Object after we create the TextNode so the TextNode appears on
the correct Level.
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
Se t myFolder - myFSO . Get Fo lder( "C: \ Oocu ments and Sett in gs \ " & _
"All Users\A pp l i cati on Oa t a\ " &
"Bent l ey \ Wor kSpace \ Projects \ " &
"Examp l es\Bui 1di ng\Ogn " )
For Ea c h my Fi 1e I n my Fol de r . Fi 1e s
Se l ect Case myFile . Type
Case "Bent l ey Mi croStation Design Fi le "
'File Nam e and Merge Cell s
myWS.Cells( CurRow, 1) = myFile.Path
myWS.Ran ge( "A" & CurRow & ":F" & CurRow).MergeCe l l s - Tru e
myW S. Range ( "A" & CurRow, "F" & CurRow) .B ord e r Ar ound _
. xl Th ick
'Header
CurR ow = Cu rR ow + 1
ITag Extraction I
709
710
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.
ITag Extraction I
711
712
BS I300A
AE20 1 1.0
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
In this chapter:
[B
[B
[B
[B
[B
[B
[B
713
714
U ~licrosoft
U Microsoft
C Microsoft
U Microsoft
U Microsoft
U ~licrosoft
U ~Iicrosoft
U Microsoft
U ~Iicrosoft
U ~Iicrosoft
U Microsoft
U Microsoft
U ~licr osoft
Cancel
Browse .. . . J
[
.
.!.l '----'----'
Help
,~~:.~!:L.~~+;;1~~#~.W.~~:0~./'4~:~d!
C:\WINDOWS\system32\STDOLE2. TLB
Standard
715
IAOOOB
:======~
~ }a
'W
L - I_ _ _ _
Classes
rffJ
rffJ
rffJ
,tfJ
rffJ
,tfJ
Me mbers of 'Connection'
~[.~~~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
14022
14023'
14024 1454454 UT
14025 ... !43!6.1 1,.UT
14026 '
14028'
1~35839UT
1429440UT
l!q~l _1!5.1.Q! .t,!T
1~9}.!. __14.!2420 !!I.
49045
.i(04S '
Tooele
L~~e. PoinICemelery . cemelery ;Tooele
... Lak. e P.9inllnler"hange ,cr9ss.ing [Tooele
. !,ake ~oi.~\.~u. ~ .~lion ... ;ppl...... iTooel.e
Lake Powell Overlook . Iocale
;Garfield
4068083 112.26222
,4Q4017N , 1121545.W , 40671}9. 11~26?5..
49. 045
' 404136N 1121547W 406~.~~3 112.26306
49.045 T404323N . 1 121 :i~iw 40.72306 .1122.2.5.28
" 4iioil ' : 375302Nll02508W 3788389 110.418B9
;La~e. Ridg;; "~f r~dge
! Ri~h ~:
~$l@.:.l~"57bji-J ill1 0?2i'l\iji .95()83 1 i 109083
L~~id~_._ ..... ~ el'L . __ .:.~alL~~'!.... _._~Q~.~ .. _._l..4.Q.41.5EN ~'!'!.?[J~8W ~Q 9~1!!.-1110716!
~,,-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::~~:
49; Q~!i.
..f~~chhe
..
:11 ;~~~~
.m
1.
717
__
--
rn~
-(~ -
Ii
Folder views
You can apply the view (such as Details or Tiles) that
you are using for this folder to all folders.
.:A
4iJlJ
". I Apply to All Folders I [,..------,
Reset All Folders
Advanced sellings:
~------~-----------------------------.
!0
A .. '
o
o
o
o
o
o
o
o
o
Restore Defaults
In the View tab, uncheck the "Hide extensions for known file types".
I.
Arrange Icons By
.'
I _~~~R:~ame
._._. ___...~I+Z
. c:;J1
,.__p_ro_p_e_
rt_
ie_
s ______________
~:Ir-~------------------------
718
If you change a file name extension, the file may become unusable .
Are you sure you want to change it?
I r::::::::x~s.~::: ~
__!i_o _-,
o KB
. 001PlacePoints ,udl 1
J ,i
Text Document
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.
,Provider
OLE DB Provider s
Connectivity Service Provider
MediaCatalogDB OLE DB Provider
MediaCatalogMergedDB OLE DB Provider
MediaCatalogWebDB OLE DB Provider
Microsoft ISAM 1,1 OLE DB Provider
Microsoft Jet 3,51 OLE DB Provider
DB
DB
DB
DB
DB
DB
DB
DB
DB
DB
Microsoft OLE
Microsoft OLE
Microsoft OLE
Microsoft OLE
Microsoft OLE
Microsoft OLE
Microsoft OLE
Microsoft OLE
Microsoft OLE
Microsoft OLE
r;;
1'"1- --------- --
Jl.lank password
~I
lest Connection
OK
Cancel
Help
OK
Cancel
Help
719
720
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
722
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
Now that we can 'connect' to a database by using a UDL file, let's take a
look at the Connection's ConnectionString property.
Sub TestConnectionK ()
Dim myDB As ADODB . Connection
Set myDB = New ADODB . Connection
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.
Sub TestCon nect i onL ()
Dim myDB As ADODB.Connection
Dim ConnectionStringVals(O To 2) As String
Set myDB = New ADODB.Connection
ConnectionStringVals(O)
"P rovider=Microsoft . Jet . OLEDB.4 . 0"
ConnectionStringVals(l)
"U ser ID=Admin"
ConnectionStringVals(2)
"Data Source= " &
"C: \Microstation VBA\PlacePoints . mdb"
myDB.Open JO i n(ConnectionStringVals. ";" )
MsgBox myDB.State
myDB.Close
End Sub
724
Xabaagua (histo~ical )
Xocotoc (histor i cal)
Verba Buena Beach
Verba Buena School
Ypuc (historical)
~]i
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
725
726
[E
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.
728
CellNa~e ".
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'.
729
730
~ote"
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
State
County
'I
:.:oJ :: :
" "j----:.:oJ"""'1
.. :::".": :::::::: : ::::: ::::'"
~~i~t';Y~~
Description
Report
Add Note
Draw In MicroStation
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:
Se l ect , Dist i nc t Sta t e fro m Po int s
The Recordset will be populated with a record for each distinct value
found in the State field. In our example here, we will place each State
field's value in the ComboBox named cmbState.
Pr i vate Sub User Form_ In it ia lize()
Dim my DB As New ADO DB. Con ne ction
Dim myRS As New ADODB . Recordset
myDB . Open "f i le name=C: \ Mi c roStation VBA\P l acePoints . udl "
myRS . Open "Se l ec t Dist i nct State from Po i nts ", myDB
Whi le myRS . EO F = Fal se
cmbState . Add l t em myRS( "State " )
myRS .M oveNext
I-Jend
myRS . Cl ose
732
When the Form is shown, each unique State is added to the combo box.
The data for this example is being taken from a database created from
information on the USGS website: http://geonames.usgs.gov/stategaz/
index.html. Although all 50 United States were available, only two were
used. One, California, is a fairly large dataset, and the other, Utah, is a
much smaller dataset. So, in our example here, only two states will be
displayed: CA and UT.
When the user selects a State from the cmbState ComboBox, we want
to populate the cmbCounty ComboBox with all of the Counties in the
selected State. But before adding anything to the cmbCounty
ComboBox, we use the Clear method on it as well as on the
cmbPointType and lstDescription controls. If we didn't Clear the
Combo Boxes, County names would continue to be added to
cmbCounty each time a State was selected so that the cmbCounty
ComboBox would no longer display only the Counties from the selected
State.
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.
Pr ivat e Sub cmbState_Cl i ck()
Dim myDB As New ADOD B.Co nnect i on
Di m myRS As New ADODB. Rprnr dse t
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.
Private Sub cmbCounty_Clic k()
Dim myDB As New ADODB . Connect i on
Dim myRS As New ADODB.Recordset
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
" &
'"
All of the above code forms the framework for allowing the user to
select Places from the database.
At this point,
the Form
looks like this:
State
county
Point Type
Description
I CA 3
I Los Angeles
I tower
Hauser Microwave Station ....................................... ................................ .......................... .i
KABC:AM(LosAngeie;;j"
Add Note
..
..:::..l
Draw In MicroStation
I SQL Essentials I
First we will look at the
resulting file, then we will look
at the code.
We have already seen how we
can get specific field values by
addressing them by name. We
could do this to create the
report. However, the goal is to
export all field names and
values. To accomplish this, we
use the Fields Collection of the
Recordset Object.
735
File
Edit
~niQue IO
Format
View
Help
71090
USGS_IO 1654661
State
CA
oes cri pti on
Haus er r,li crowave Stat, on
pointType
tower
county LOS Ange l es
TypeA
6
TypeS
037
LatOM S 343249N
LonOM S 1181256W
LatOec 34.54694
LonOec -118.21556
Ref _LatOMS
Ref _LonO~IS
Ref_LatOec
0
Ref_Lonoec
0
Elevation
0
population
0
FederalStatus
CelHlame
Ritter Ridge
736
Form
frmAddNote
~~;e:B;; Ir--_.......:.._""'--_____
Note: ..
.. .
. ,' ,
...
( .... ...............
OK
When the user clicks the OK button, the following code is executed:
Private Sub btnOK_Click()
If frmAddNote.Tag =
Then
MsgBox "AddNote not executed correctly."
Unload Me
End If
If txtNoteBy . Text = " " Then
MsgBox "Please enter Note By. "
Ex i t Sub
End If
If txtNote.Text = " " Then
MsgBox "Please enter Note. "
Exit Sub
I SQL Essentia ls I
737
En d If
Dim myDB As New ADODB.Connection
Dim myRS As New ADODB.Recordset
Dim myField As Field
Dim FFile As Long
myDB.Open "fi le name =C: \MicroStation VBA\PlacePoints . udl"
myRS.Open "Sele ct * from Place Notes Wh e re UniqueID = 0 ", _
myDB, adOpenDynamic, adLockOptimistic
myRS . AddNew
myRS( "NoteBy " ) = txtNo te By . Text
myRS( "T heNote " ) = txt Not e. Text
myRS( "Place I D" ) = fr mAddNote .T ag
myRS( "NoteDa t e" ) = Now
myRS . Update
Msg80x "Note added ."
Unl oa d Me
End Sub
but we would take a huge performance hit because we are opening every
record in the Table. By intentionally opening a Recordset without any
records in it, the Recordset is opened almost immediately because it
does not need to retrieve any data.
The last button we are going to discuss is the Draw In MicroStation
button. The Database we are using has Latitude and Longitude values in
it, which give us Y and X values of the 'places' in the database. We will
use these values to place a Circle and Text Element at the location of the
selected 'Places' from the database.
First we will look at the code behind the button and then we will look at
the results.
738
We use the LonDec and LatDec fields for the X and Y elements of each
Circle Center Point and Text Origin. We display the Description field's
value as a TextElement in MicroStation.
In the previous buttons we used, our work was based on the Listlndex
property of the Listbox. Since we are drawing in MicroStation, we want
to allow the software to place multiple points with only one button click.
This is why we are looking at the Selected Property of each item in the
I SQL Essentials I
739
740
We only add two lines of code to the Click Event ofbtnDrow and we add
a Function named Chec kLeveL Now, all Places selected are added to the
ActiveModelReference on a specific Level. The Level matches the
selected "Point Type".
As our program stands right now, we have some very good functionality
in place. We can get a report based on the selected item in the listbox.
We can add a note to the selected item in the listbox and we can draw
items selected in the ListBox inside the ActiveModelReference in
MicroStation.
741
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
MyDB.Open "File name=c:\MicroStation VBA\rss.udl "
MyRS.Open "http : //www.wired.com/rss/index . xml". MyDB
Whi l e MyRS. EOF = Fa l se
Set Channel RS = MyRSC "channel " ). Val ue
While ChannelRS.EOF = False
Set ItemRS = ChannelRSC"item " ).Value
While ItemRS . EOF = False
Debug . Pr i nt I temRSC "tit l e " )
Debug.Pr i nt vbTab & ItemRSC "link " )
Debug.Print vbTab & ItemRS( "description " )
ItemRS.MoveNext
Wend
ChannelRS.MoveNext
742
Wend
MyRS.MoveNext
Wend
End Sub
When Rea dRSSA is executed, the RSS of the wired. com website displays in
the Immediate Window. Since RSS files are usually updated fairly
frequently, the results shown in the Immediate Window will be different
from day to day and may even be different from hour to hour.
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
the SlUl
t~~j
,}11
743
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:
Private Declare Function ShellExecute Lib "shel 132 .dl l "
Alias "ShellExecuteA "
(ByVal hvmd As Long , _
ByVal lpOperation As String,
ByVal lpF ile As String, _
ByVal lp Para me ters As String, _
ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As Long
744
End Sub
Private Sub UserForm_Initialize()
Dim MyDB As New ADODB . Connection
Di m MyRS As New ADODB . Recordset
Di m Channe l RS As New ADO DB. Reco rdset
Dim ItemRS As New ADODB.Recordset
MyDB.Open "File name=c: \ MicroStation VBA \ rss.udl "
MyRS.Open "http://rss.news.yahoo.com/rss/tech'', MyDB
While MyRS.EOF = False
Set ChannelR S = MyRS ( "chann el" ) .Va l ue
Whil e ChannelR S. EOF = Fals e
Set ItemRS = ChannelRS(" item " ) .V alu e
Whil e I te mRS .EOF = Fal se
lstR SS . Addl tem Rep l ace( Item RS( "t itl e " ) , vb Lf, "" )
l st RSS .Li st (lstR SS .Li s t Coun t - 1. 1 )
ItemRS.MoveNext
Wend
Ch annelR S. Mo veNex t
Wend
MyR S.M oveNext
Wend
End Sub
Likely, RSS feeds will be used more frequently. As they do, this code will
become more important and more useful. For example, a company
could create their own RSS feed on their Intranet to display assignments
for personnel. What project am I working on today? Open my RSS
reader and it tells me.
745
746
Edit
Format
View
Help
747
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
[B
adLongVarChar
[B
[B
= 201
748
(DBTYPE_R4).)
[B adSmallInt
(DBTYPE_I2).)
[B adTinyInt
(DBTYPE_Il).)
[B adUnsignedBigInt
integer (DBTYPE_UI8).)
[B adUnsignedInt
(DBTYPE_UI4).)
[B adUnsignedSmallInt
integer (DBTYPE_UI2).)
[B adUnsignedTinyInt
(DBTYPE_UIl).)
[B adUserDefined
(DBTYPE_ UDT).)
[B adVarBinary
[B adVarChar
[B adVarNumeric
[B
character string.)
[B adWChar
string (DBTYPE_WSTR) .)
The Database PlacePoints.mdb has a Table named "Points", and a Table
named "PlaceNotes". When we look into the Schema we can see that
Tables named "MSysAccessObjects" and "MSysAccessXML" also
display. It is not uncommon for databases to create their own tables for
functions such as the indexing of indexed fields. In most cases, it is clear
which tables are 'system' tables and which tables are for our use.
749
Provider
i j
61
Next
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:
Itowerdat.xls
Files of type:
!AIIFiles ["")
~I
Cancel .
//
750
r ' 1- - - - - - - - - - -
Provider
I C~nnection I Advanced
All
Extended Ploperlies
Jet OLEDB:Compact With...
Excel S.O ~
Faf~e
751
1
2
3
4
1R4?7
D
Z DATASET
??444
514 xy=18325.22791.514
526 xy=18414.22609.526
4h~ ",,=1 R4?7 ??444 4h~
1R1q?
??~R?
R4~
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
created that contains the
Database Schema of the
Excel file. Let's open it and
take a look at it. It is
named DbSchema. txt.
File
Edit
Format
View
Help
752
Now
we
are
getting
somewhere. We are able to get to the data in an Excel file without
opening Microsoft Excel. For that matter, Excel doesn't even need to be
installed on the computer.
Let's see what else we can do.
Sub Test DBExcelB ()
Dim myDB As New ADODB.Connection
Dim myRS As New ADODB.Recordset
Di m CenPt As Point3d
Dim myCircle As ArcElement
Dim RotMatrix As Matrix3d
myDB . Open "file name=C:\MicroStation VBA\Excel . udl "
myRS . Open "[TOWERDATS ]", myDB, _
adOpenDynam i c, adLockOptimistic
While myRS . EOF = False
CenPt.X
myRS( "X" )
CenPt.Y = myRS("Y" )
CenPt.Z = myRS("Z")
Set myCircl e = CreateArcElement2(N othing, _
I Review I
753
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
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
[B Adding a Reference and using the Object Browser
[B Basic Macros that communicate with Mathcad
[B Region Objects - The Basis for All Calculations
[B The Mathcad Object Model
[B Driving MicroStation Geometry from Mathcad
755
756
~vailable References:
---===---_._----_._..,
0d
...
OK
Cancel
!l.rowse ...
rl Mp,<;<;p.nnp.r PrivAtA
Priority
~
[
.
Vi
t,.~j
<=;i""
l:~=-='k=:_=
~r
=U==
_':'
- =.. . ,=-=
-JI, --______"']j, Mathcad 12 Automation API ....
.. ..
Location:
C:
Language:
Standard
tlelp
'---="-'----J
757
Once a Reference has been added, we can use the VBA Object Browser
to 'browse' the Mathcad Object Model.
Me mbers of 'Application'
Classes
(j
~ ActiveWindow
<globa ls>
~ ApPlication
IlI
~ CustomMetadataC oliecti on
~ Applic ati on
~ DefaultF il ePath
AcliveWorksheet
'''~ CloseAIi
~ IM athcadReg ion2
~ IMathcadWorksheet2
~ IM ati1cadWo rks heets2
~ IMetadata
~ Mathcad Old
~ Mathlnterfa ce
~ MatrixVa lue
riP MCApp Option
riP
MC CustomM etadataType
,t p MCF ileFormat
riP
riP
rfjJ
riP
~
~
~
~
MCReg ionType
MCSaveOption
MCWindowState
MCWorksheetOption
Numeri cVa lue
Region
RegionMetadata
Reg ions
fJ
fJ
Wi ndowActivate d
Wind owDe activated
~ Windows
fJ WorksheetClo sing
fJ WorksheetOp ened
ii i
~ Worksheets
Class AlllllicatiQII
Member of M"thc""
Malhcad Application Object
758
'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 ~~~ '"'{,~ ~
jl Narmal
v ;IAr;al
J~ <~ r~ ajJ ~
@D= ~ ~r:
vJL B I
!! r~2:E
IH~~_
e
_______.
StrikeShim :=
~in
MaxLength :=
300em
:MinLength :=
50 em
759
H""~~.f:'"
'~~"<v_,"'<"
.....
\"~'
.....
""-.
<
A~
'''T~''''''''
."......."
"""''''
Classes
~ Regions
~ StringValue
~ Va lue
~ Window
~ Windows
g[~~~t~~:::~l~tadaia
~ Works heets
,v
760
0, 0254
CE
If
~0 00 0B
800000
GD [Q Q C2JOG
B0GDGJD
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
Integer
Real
Type
Double
Long
Double
string
6
5,6134
"Numeric"
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
761
5. 6 134
a
6
5 .6134
Numeric
i-UOK ---]1
Sub TestMathcadB()
Dim myMCA As Mathcad.Application
Dim myMCW As Mathcad.Worksheet
Dim myMCV As Mathcad.NumericValue
Set myMCA
GetObj ect ( . "Mathcad.Application")
Set myMCW = myMCA.ActiveWorksheet
Set myMCV = myMCW.GetValue( "RoughLength " )
MsgBox myMCV.AsStr i ng & vbCr & _
myMCV.lmag & vbCr & _
myMCV. l nteger & vbCr & _
myMCV.Real & vbC r &
my MCV .Type
End Sub
762
~~~!!tt!iSv~~t~~!sl\}'&t,~~~ ~. ">~;*~,,
,/
...
~ ~'!'-:~w~~=.<;:'"tJ..~~
vv o "
<'1;;
763
myMCSV . Value
End Select
End Sub
converting it to Inches.
Rough Length: 221 Inches.
OK-~
764
JambShim:=
765
StrikeShim := ~in
2
MaxLength := 300cm
:MinLength :=
SOcm
766
IMathcadWorksheets2
767
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
~ IM ath ca dRe gion2
~ IM athca dWorks heet2
~ IMathcadWorkslleets 2
li!IJ
IMetadata
~ Mathcad Ol d
li!IJ
li!IJ
MatrixValue
rfjl MCAppOptio n
Class Mathlntenace
Member at Mothcad
Mathcad Mathlntertace object
When we run this macro, the XML property for each Mathlnterface of
each IMathcadRegion2 Object is written to the Immediate Window.
Here is an example of what is written when we run TestMathcadE :
<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
This is the data that is associated with the RoughLength variable in our
Worksheet. Let's take a look at a few more:
<ml :define xmlns:m l=''h ttp://schemas .ma thsoft.com/math20 '' >
<ml :id xml :space= "preserve ">JambShim</ml :id>
<ml :placeholder/>
</ml : defi ne>
<ml :define xmlns:ml=''http://schemas.mathsoft.com/math20''>
<ml :id xml :space= " preserve">StrikeShim</ml :id>
<ml:apply>
<ml :mult style="auto-select"l>
<ml:apply>
<ml:div/>
<ml : rea l >l</m l : rea l >
<ml: real >2</ ml : real>
</ml:apply>
<ml :id xml :space="preserve">in</ml :id>
</ml:apply>
</ml : defi ne>
<ml :define xmlns:ml= '' http://schemas.mathsoft . com/math20''>
<m l : i d xml :space="preserve">Max Length</ml :id>
<ml:app l y>
<ml :mult style="auto-select"l>
<ml :rea l >300</ml :real>
<ml :id xml :space="preserve">cm</ml :i d>
</ ml:apply>
</ ml : de fi ne>
769
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
Path
Windows
FullName
Quit
Worksheets
770
IMathcadApplication2
Active
Height
Top
ActiveWindow
HWND
Version
ActiveWorksheet
Left
Visible
Application
Name
Width
CloseA l1
Parent
Windows
DefaultFilePath
Path
Worksheets
FullName
Quit
GetOption
SetOption
771
Width
:~
1ft
Height
:~
2ft + 2in
HoleDia:~
12nun
MaxSpacing
:~
50nun
OutsideBuffer := 50ml1\
CaicuiateQuantity(Overall)
:~
Overall - OutsideBuffer 2
------HoleDia + MaxSpacing
QtyWidth := trunc(CaicuiateQuantity(Width)) + I
QtyHeight := trunc(CaicuiateQuantity(Height)) + I
ActualSpacing(Overall)
:~
Overall - OutsideBuffer 2
QtyWidth
SpacingX1n
:~
ActualSpacing(Width)
Sp acingYIn
:~
A ctualSp acing(Height)
- HoleDia
HoleDiain := HoleDia
OutsideBufferln :~ OutsideBuffer
Widthln: = Width
HeightIn
:~
Widthln
H eightIn
Height
17 in
26 in
QtyWidth
QtyHeight
6
10
SpacingX1n~
1.705 in
3.205 Ul
SpacingYIn
H oleDiain
0.472 in
OutsideBufferln
1.969 in
772
When using Mathcad, we can allow the parameters for our plate to
be entered using a large variety of units. For example, the Hole
Diameter can be entered in millimeters and the width and height
can be entered in decimal feet. The 'buffer' can be entered in yards
and the Maximum Spacing can be entered in cubits. The units used
to enter the design parameters are almost irrelevant because
Mathcad takes care of the unit conversions for us. Furthermore,
when we retrieve the value of any variables in the Worksheet, we can
specify in what units we want the value returned.
773
>
Here we can see a "define" Region and an "eva!" Region. Notice how the
"eva!" Region has an "id" value of "Widthln" and a "real" value of" 17':
These are the Region values of interest to us.
When we want to retrieve a Region from Mathcad, it is best to retrieve
all Regions in the Worksheet at once in a separate function and then
parse them to find the values we are looking for. We will begin with a
Function named GetA 11 Regi ons.
Function GetAllRegions () As String
On Error GoTo errhnd
Dim myMCA As Mathcad.IMathcadApp l ication2
Dim myMCW As Mathcad.IMathcadWorksheet2
774
775
=
=
Now that we have the Region Values we can begin the process of making
use of the values and drawing the plate and its hole pattern in
MicroStation.
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
FilterReturn = Filter(AllEvals, "Widthln= " )
PartWidth = CDbl (Replace(FilterReturn(O), _
776
The Array AIlEvais is 'Filtered' to get only the parameter we want. When
we find it, we get the value associated with the parameter by replacing
the parameter name and the equal sign 'with an empty string and then
converting the remaining text (the numeric value) to a Double by using
the standard VBA CO b1 function. Each of these parameter values are
placed into their own variable. These variables are then used to call a
procedure named OrawPart.
CreateL i neElement2(Nothing, _
Point3dFromXY(O, 0), _
POi nt3dFr omXY( Width, 0))
Act i veModelRefere nc e . AddE l ement myL in e
Set my Line
Set myLine
Se t my Li ne
CreateLineE l ement2(Nothing , _
Point3dFromXY(Width, 0 ) , _
Point3dFromXY(W i dth, Height) )
ActiveModelReference.AddElement myLine
Crea te Lin eE lement 2(Noth in g , _
Point3dFr om XY(Width, Height), _
Point3dFromXY(0, Height))
ActiveModelReference.AddElement myLine
CreateLineE l ement2(Nothing, _
Point3dFromXY(O, Height), _
Point3dFromXY(0, 0))
Ac t iveModelReference.AddElement myLine
XPos = OutBuffer + HoleD i a / 2
For X = 1 To OtyWidth
YPos = OutBuffer + HoleDia / 2
For Y = 1 To OtyHeight
' *** Draw the Circle ***
Set myCircle = CreateEllipseElement2(Nothing,
Point3dFromXY(XPos, YP os ) , HoleDia / 2 , _
HoleDia / 2, RotMatrix)
ActiveModelReferen ce.Ad dEl emen t myCir cl e
777
778
The code is in place. Our Mathcad Worksheet is open and the design
criteria has been entered. The only thing to do now is run the procedure
DrawFromMathcad and see how the calculations we entered into Mathcad
look.
o
779
780
781
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.
C alculat eQ uantity( 0 verall) : =
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
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
[El
[El
[El
[El
When to run macros from within Excel and when to run them
from within MicroStation
[El
783
784
COM BASICS
785
Available References :
OK
Cancel
Browse ...
-.!J
~: ::;,'~- gL-~~~-,,]
Help
,Lei
C:\Program Files\Messenger\msmsgs.exe
Language:
Standard
We have seen this before. Let's talk a little more about what we are
actually seeing.
786
Look in:
IeJ system32
:::J
+-
d IITI
1~
~, 3com _-dmi -------------~
-1 0-41---
1~ 1~5
IB 1~8
~ 1 ~2
~1~4
1r(::) 1031
B2052
ifC:l 1037
fC:l appmgmt
IB 1 ~
B ~~
Ii5!,':
.. ,
I. Open
File name:
Files of type:
Cancel
Help
787
Are we doing early binding or late binding here? Late binding. Why?
Because we declare the variable mylnet as an Object. Declaring a
variable as an Object provides for a generic Object that could be an
Internet Explorer Application, a Line Element, or a Database
Connection. The variable does not know what type of Object it is until it
is Set with code such as:
Set mylnet
After this line of code is run, the variable mylnet knows what type of
Object it is. When we use late binding, Intellisense is not active because
the variable does not know what type of object it is.
Sub Run I nt e rn e tExpl orer()
Dim myInet As Ob j ect
Set myIn e t = Cre ate Obje c t("InternetE xp l o rer.Appli c ati o n")
myInet.
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.
my In e ~ !~~:~f.~:~~:~:~~:::: ::::::::::::::::::::::::::~ ~
www.bentley.co m "
NsgBo ~ Application
si t e. "
myIne @' Busy
/"WWW.micros oft . com "
~lsgBo ,~Cli entToWi ndow
ebsite."
End Sub
@' Container
~ Doc um ent
I
v
"'~ ExecWB
:.
788
IL~:~:::::~:::::~
Run-time error '429':
ActiveX component can't create object
~d
tielp
789
Noth i ng
790
Nothing
791
792
793
If we can control MicroStation from Excel and can control Excel from
within MicroStation, when do we write code in MicroStation and when
do we write it in Excel? That is a good question. There are several things
that we should consider. They are not listed in order of importance
because the importance of any particular item probably depends on the
situation in which we find ourselves at the moment. For the sake of
discussion, we will use MicroStation and Microsoft Excel as the two
applications in which we are developing.
[B Is MicroStation installed on this computer? If we develop in
794
[B
Choosing the best tool for the job should always be near the top of the
list of things to consider before developing an application. We have
listed several things worthy of consideration and there are others that
may pop up that are specific to a project or task.
795
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
,t~~ Q I ~
Insert
FQ!mat
Q.ebug
,\f1.~
MIl
r' I
'-'1
Bun
.UJ
10015
0
l.dd-lns
~ I ~ @"
'Wndow
tlelp
W '~~ l @ I, Ln I, Coil
VBAProject
f"l
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
Set myMSAppCon = GetObject( .
"MicroStationDGN.ApplicationObjectConnector " )
Set myMSApp = myMSAppCon.Application
CurRow = 2
For Each myLevel I n myMSApp.ActiveDesignFile.Levels
Sheet1.Cells(CurRow. 1) = myLevel.Num ber
796
myLevel . Name
Next
End Sub
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
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
Set myMSAppCon = GetObject( .
"MicroStationDGN . ApplicationObjectConnector " )
Set myMSApp = myMSAppCon.Application
797
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
Default
Existing Terr ain
Building SiteTerrain
ExistingTerrainM esh
Frame
Buil " iteMesh
,;;;
, Number !
0
1
2
3
Description
File
Logical
Chapter 17_""
Chapter3?_""
Chapter3?_""
Chapter3?_ ""
Chapter3?_"
Chapter3?_ "
Master
Master
Master
Master
Master
Master
EJ
Do
Do
Do
Do
Do
Do
798
~ta.
:tlindow
Standard
'"
Formatting
;.,:. r' - -
L
,rr
tielp
Borders
Chart
r[f~~i~~;~j L .commands II
Control Toolbox
, Toolbl's:
External Data
--
,h
DBorders
i DChart
1 D Chart Menu Bar
. D Circular Reference
D Compare Side by Side
D Control Toolbox
DOiagram
DOrawing
DOrawing Canvas
D Exit Design Mode
D External Data
DForms
D Formula Auditing
Forms
Formula Auditing
List
....
Picture
....
PivotTable
.~--
Protection
- Iri
,,-~
...
1'---"
._-
Reviewing
Task Pane
Watch Window
.- ..
t,
P.endm~.:.~.:..,... J
~eset ...
Attactl..
dose
Visual Basic
.....
A~
Text To Speech
......
-.-
Qptiona _ _ _ _ _ _ _ _ __
Standard
I ~
i 0 Formatting
i D 3-0 Settings
Drawing
0.e
Web
WordArt
"'-"
-_..
.---
S;;ustomize. .. I\.
'\\
I oolbar name:
.~oStation VBA
Ii
OK
iJ I
Cancel
And now for a warning: the new toolbar is very small because it
does not have any buttons or menu items in it.
799
Drag and drop "Custom Menu Item" into the new toolb ar we just
created.
0~1~~J ~ommands 1itio~ L._.______. __ ._. __
II Tocommand
add a command to a toolbar: select a category and drag the
out of this dialog box to a toolbar,
I ~.:
! Dwindow and Help,:,:
I A~~~~~~pes
I !'pGlult
co
rr=m=m=an=Q.=s:= = = = = = = . " . 1, C lC
Iio
tom ~lenu Item
'
~m Button
I
......_.'il"I
Builtin Menus
New~lenu
fYlodify 561ectiorJT
.~._..
_ _
_ _ _
__ _ _ _ _ _ . . ... ....
Close
Next, right-click on the new Menu Item and take a look at the
context menu.
~opy
Button Image
Button Image
Assign !:!yperlink
Assign Macro ...
800
Mcros in:
Description -
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.
We may see
someth ing
like this:
"C: \Microstation
Macros may contain viruses, It is usually safe to disable macros, but if the
macros are legitimate, you might lose some functionality,
[:,,:ij~:~~(~0~si;;:s.,::,:JI
........,;:,.!;.n_ab_leM_a_cro_s "'i~
L----=t1o_re_In_fo_-'
801
Assign Macro
~l cros
in:
Description ....
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 XLMS A()
Dim myMSAppCon As MicroStationDGN . ApplicationObjectConnector
Dim myMSApp As MicroStationDGN.Application
Dim my Level As Level
Dim CurRow As Long
Set myMSAppCon = GetObject( ,
"Mi croStationDGN . ApplicationObjectConnector " )
Set myMSApp = myMSAppCon.Application
CurRow = 2
For Each myLeve l In myMSApp.ActiveDesignFile.Levels
Sheetl.Cells(CurRow,l)
myLevel . Number
Sheetl.Cells(CurRow, 2) = myLevel . Name
CurRow = CurRow + 1
Next
End Sub
802
The changes are small but the significance of the changes are not. Let's
now assign XLMSC as the macro to run when the menu item is selected.
After we do so, the workbook Book 7.xls is still opened when the menu
item is selected but the Levels are placed into the worksheet that was
active when the menu item was clicked. So, the code is working better
but to have our Workbook open inside Excel each time someone clicks
the button in Excel can be improved.
It makes perfect sense that prior to running a macro, the file in which
the macro resides should be opened. But when we click a menu item we
expect code to run, not workbooks to open and dialog boxes to be
shown asking us to enable macros. So, what is to be done?
803
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.
Save tn:
...~
La
~ly Recent
Documents
trr~:il
J1
'." .':.\
Desktop
[.;.I.
LQ!licrostation VBA
Too!s
Illbcd material
!l!b docs
iifC:)Documents
!il,:",", Fonts
Iif$ fr om mark
I i!O PlcS
II~
~~~~e
ia
My Documents
'i
r~y Computer
'
My Network
I rl
Places
1!!bBatchProcessing
Code
VB6
i
I
,~Fi;le~na~m~e~:~~~~@W~
l"" . ~*~~~j~m~i'
... ..... ~$~~a~mm~m~~~~
....... ..... ............
! save as
~ype:
addIns available:
I.
OKi
Cancel
!O Getpricing
!O Internet Assistant VBA
iO Lookup Wizard
iO Solver Addin
Analysis ToolPak
Provides functions and interfaces for financial and
scientific data analysis
I.
804
Look in:
I~
l;W
My Recent
Documents
rr-;:~
~
Desktop
i'<v~).
t{::!J
II
IrQlFonts
IrQl from mark
rQlpics
jrQI Source Code
,'rQl USGS
IOVB6
Mi-:roStationV6P,?Md-In,xla
My Documen~s
jlID
My 'Computer
'I
Analysis ToolPak
~rowse",
'P'
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
~'ac ro
name :
i~----~--~ ~-i ~
L._.______
~'9.cros
in:
A _ _ . _ . _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
I
I
I
_1
E,j:t
r'2Cyj",
Open Workbooks
Description
9 After clicking OK in the Assign Macro dialog, click the Close button
in the Customize dialog box and we can test the Menu Item.
When we click the Get DesignFile Levels button now, the macro is
executed immediately because the Add-In is already loaded. If we
change from "Sheetl" to "Sheet2" and click the menu item again, the
Levels are displayed in "Sheet2". Remember, in our code, we are writing
to the ''ActiveSheet'' now so the active sheet in Excel will receive the
Level information.
When we created the Menu Item, we named it "&Get DesignFile Levels".
The Ampersand (&) character specifies which character will be
underlined in the Menu Item. The underlined character means we can
hold down the <Alt> key and press the <G> key (the underlined
character) on the keyboard and the menu item will be 'clicked'. This
means that in addition to clicking the menu item in Excel, we can
perform an <Alt+G> on the keyboard and the macro will run.
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
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
[B
[B
[B
DIFFERENCES BETWEEN
VBA and VB6 have a great deal in common. Of course, they both make
use of the language, "Visual Basic". Projects are broken out into Code
Modules, User Forms, and Class Modules. Each environment allows
References to be added to the project. There are also some differences.
[B
807
808
[B
[B
[B
[B
[B
809
New
IExisting I Recent I
Wnw
'0,'.
~.
VB Wizard
~tanager
,.",
'0,'.
.9;i
l?r
~ .
W
ActiveX EXE
ActiveX DLL
ActiveX
Control
VB Application
Wizard
Addin
Data Project
ActiveX
Activex
Document DII Document Exe
.....
,.",
"'.
open~
Cancel
Help
810
Alphabeti~
, , , , , . ' : : : : : : : : : : : : : : :: 1""""",..- --
::::J
jForm! Form
lcategorized!
AutoRedraw
... . .,.'"
-,
1=l1J.
"
.: : : :. :::: :<
.........-' '-''- "....
' ' "",
' '- '- ' ....
' ' -'
Eel.. -'-'"" .
c; g'E:l
False
'&H
"-8'O:'O':'O:-O:O:~O- 1
. . . . .. , . ., '
.
-11
[G A f85T
f(9 , '-
'.zl
@j
~~
::11
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
place a ComboBox, a Label and
a CommandButton on the
Form.
level
Execute
811
The Make Project dialog box displays and here we specify a file location
and a file name.
r------------c~-----------------------_,
File name:
IP,oiect1 .exe
~
Cancel I
Help
Qptions...
Execute
When we save our project, we are asked to supply the names and
locations for two files: Form l.frm and Project 1.vbp. This differs from
VBA where we are only asked to supply the name and location of a
single .mvba file.
Just to review, we have created three distinct files at this time. We
created a .frm file (User Form), a .vbp file (VB6 Project File) and an .exe
file (Compiled Executable). When we are ready to distribute our
application to others, of these three files , the only file we need to
distribute is the .exe file.
Project - Projectl
Project! (Projectl)
Forml .
. El l'1l!p-!II!!
.I!II
. ,,1m""""',",
. I!!I
.. in
..
E!!il
,<L .. '::'w~'"
ViewOWect
1m View CQde
Iformi Form
"
'
'
'
~ ~ Prope[ties
_
812
2ave Forml
Save Forml 8.5".
File.
- - - - _......_-"--_.
r;-
Doc!!,;ble
tlide
Component" ,
Look in:
Iell VB 6
File name:
IForm1.frm
Qpen~
Files of lYpe:
Cancel
J:!elp
813
Level . . Combo 1
Cell
I.-Co-m-bo-2----------,
Execllle
I:: :
_ _ _ _--.l.
The first Project we created was named "Project!': This is the name
VB 6 gave it. We want to name this one "Project2". We do this by going
to the VB6 menu and selecting Project> Projectl Properties.
Generall
Startup Object:
IStanchrd cXe
Project Name:
IProject!
~ lii1&mii=iiliiM~
Project Help
Context ID:
fO
Project Description:
OK
Cancel
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
General
Project Type:
tStaf1d~~rd EXE
2):artup Object:
-=:J lMSH,!
Project t:/ame:
1Project2
-,::::J
Project Help
Context [D:
10
Eroject Description:
Unatt~nd.~d Execution
P'
r
r
r.
Tnrea:j PQ.:JI
~ threads
Retained In ~hJmor)l,
~at1cel
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.
Save in:
Ib
V86
i~ Projectl, vbp
File name:
jli1lll1llilliiJ
Save as type:
Save
Cancel
Help
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.
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 recompile 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
(E
(E
Thus far we have created two "Standard EXE" projects. There are two
other note-worthy projects and they are:
816
VB6
817
OK
Cancel
Browse ...
Priority
Help
Li
r- Bentley MicroStation DGN 8. 9 Object Library .- .......--..- ..- ..- ----..--.--.-- ... -... ..-.......
Location:
C:\Program Files\BentleY\MicroStation\ustation.exe
818
1_liimMi\il.riMiiiIiI1~
Execute
819
820
L.:J BatchProcessing
I2J cd material
CJ docs
EJ Documents
EJ Fonts
CJ from mark
ILl pies
EJ Source Code
EJ USG S
EJ VB6
filel.d
filel 0.dgn
file2.dgn
file3.dgn
file4.dgn
fil e5dgn
file6.dgn
file7.dgn
file8.dgn
file9.dgn
filea.dgn
fileb.dgn
rasterdocs.dgn
Levell
Level 2
Level 3
Level 4
I Level 5
Level6
Level 7
Level 8
,
I
.LeveI9
Level 10
jLeVelll
Level 12
.--~
821
iiiffil _ _......
1-_
Let's take a look at the code now that we know what the program is
going to do:
'General Declarations Area
Dim myMStationC As MicroStationDGN.ApplicationObjectConnector
Dim myMStation As MicroStationDGN.Application
Private Sub Form_Load()
Set myMStationC = GetObject(.
"MicroStat i onDGN.ApplicationObjectConnector " )
Set myMStation = myMStationC.Application
End Sub
Private Sub Drivel_Change()
Dirl.Path = Drive l .Drive
Listl.Clear
End Sub
Pri vate Sub Di rLChange()
Filel.Path = Dirl.Path
Listl.Clear
End Sub
Private
Dim
Dim
Set
Sub FileLClick()
myLevel As MicroStationDGN. Level
myDF As MicroStationDGN.DesignFile
myDF = myMStation.OpenDesignFileForProgram(
Dirl.Path & " \ " & Filel.FileName, True)
Listl.Clear
For Each myLevel In myDF.Levels
822
823
New
Existing I Recent I
Standard EXE
ActiveX EXE
ActiveX DLL
[II
""~
""
'3\"
~.
VB Wizard
~lanager
17
ActiveX
Activex
Document DII Document Exe
""~
....
fj:'
VB Application
Wizard
Addin
Data Project
v.
~
Open
Cancel
Help
~~m~m'fiil_lFJ
Control to
"msvba_modeltree".
Categorized
::;]
~~!?~.~~~deltree
~s.~.e.~~.~.~.Y.~
Ali9nable
.: F~I;~
: 1 - 3D
~~p'~"r an~e __
click "Components", and
AutoRedraw
select "Microsoft Windows
Common Controls 6.0" in the list. Then click the OK button.
Controls
~~icrosoft Windows
L~Iicrosoft Windows
Ct r'Iicrosoft Windows
[J Microsoft Windows
.....
r;]
________l
Browse".
V i
>
Location:
-:
C:\WINDOWS\system32\filemISO.ocx
--.---.. -.-----.--.-----.------------------.--~
OK
Cancel
824
Display the Models in the Active Design File in the Tree View
under a top Node of "Models".
[8
Display the Levels in the Active Design File in the Tree View
under a top Node of "Levels':
[8
[8
[8
825
Next
myNode.Sorted = True
' Levels
Set myNode = tvl . Nodes.Add(, , "tvlLeve l s ", " Levels " )
For Each myLeve l In myMSApp.ActiveDes i gnFile.Levels
t vl.N odes . Add " tvlLevels", tvwC h ild, "lvl_" & myLevel.Name,
my Leve l .Na me
Next
myNode.Sorted
End Sub
True
826
Now, let's take a look at the Events in which we have placed this code to
make sure we are clear on what is happening.
827
Function GetModelO As
MicroStationDGN.ModelReference
Similar to GetLevel, GetModel returns a Model Object if one is selected
in the Tree View.
828
1 Select File> Add Project. (Don't click "New Project"; we need to Add
a Project.)
. to}a
User Controls
EJ.a
L..
Forms
Form! (testingmodeltree .frm)
t:J.
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.
'.
829
OB..:J~
re,gjJ~
When we run our new Project, the Form is displayed and the Tree View
is available.
Models
. Building and E"isting Mesh
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
En d If
End Sub
Now, type:
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:
."i)
li::.:::::i:*:::::ij
This registration step is necessary on any computer where we want to
make use of the Control. If this registration step is not performed, the
Control will not be available.
Now that we have compiled our ActiveX Control, let's take a look at it
inside MicroStation's VBA environment.
After inserting a new Form in a MicroStation VBA Project, right-click
in the Toolbox and select Additional Controls.
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 ~~
o M5\11 ebDVD Class
Show
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
___"'",",._
New
.;;..;0.=
........_ ..._
IExisting I Aecent I
m
w
VB Wizard
Manager
ActiveX
Act ivex
Document DII Document Exe
~,.
~.
ActiveX
Control
VB Application
Wizard
Addin
Data Project
Open
Cancel "
Help
I'
833
General
Project I ype:
l!ilm~I!I!IIl-~:J!~mii;i2iilfi.ii!lr!!!r.!: :J: J. .
Project
~tartup Object:
i(None)
~a me:
1msvba_WinAPI
Project Help
Context 10:
10
E.roject Description:
r
P
------i
:::J ii
.
odel
Unatt!londed Execution
[ Threading t1
.
IAPartment Threaded
!,!pgrade ActiveX c ontrols
~
.~ ::~:::~:(~i~,~~:~~,:~::
r.
r.
Help
834
""J'
:'..7 .....
...,.::;..~ _.
~"
I Compile
~o Compatibility
r.
r
!:roject Compatibility
Component
IDebugging I
!linary Compatibility
OK
f'.- I
Cancel
Help
As Long) As Long
Pr i vate Declare Function GetComputerName Li b "kerne132" Alias _
"GetC omp uterN ameA " (ByVal lpBuffer As String.
nSize As Long) As Long
Private Declare Funct i on GetDiskFreeSpace Lib "kerne132 " Alias
"GetD i skFreeSpaceA " (ByVal lpRootPathName As String. _
l pS ec t or s Pe r Cl uste r As Long. _
l pByt esPe r Sec t or As Long ._
l pN umber Of Fr eeC l us t ers As Long.
l pTot alN umb erOfCluste r s As Long) As Long
Private Declare Function Get LogicalDriveStr i ngs Lib "kerne132 " Alias
"Get Log i calDri veS trin gsA " (B yV al nBuffe rL ength As Lo ng. _
ByVa l l pB uffer As String) As Long
Private Declare Function LogonUser Li b "Advapi32 " Alias " LogonUserA "
835
lpFil e As String . _
lpParameters As String. _
lpDirectory As String. _
nShowCmd As Long) As Long
0
836
Available References:
OK
I.
'. 1
. Cancel "
Browse .. ,
+1
837
We have discussed previously the fact that we can place code into Class
Modules and use them in our code. When we compile the Class into an
ActiveX DLL, it makes the code much easier to use. Multiple VB and
VBA projects can now 'attach' to our ActiveX DLL.
Just as with the ActiveX Control, this DLL file must be registered by
using Regsvr32.exe before it can be used on computers other than the
one on which we are developing the DLL. When we compile the DLL file
in VB6, VB6 registers it for us.
This ActiveX DLL can be used by other VB6 Applications as well as
VBA Applications developed in MicroStation VBA.
838
Project
~ Qpen Project".
Ctrl+N
Ctrl+O
Agd Project".
Remove Project
ctrl+S
~ erint. ..
ctrl+P
,MiMM#WWU4i\f*"
~lake Project !aroup...
.,
TestSystemDLL..vbg
~ msvba_WinAPI. vbp
~ msvba_modeltree.vbg
:1 Projectstructured. vbp
It
Alt+Q
839
(ivailable References:
OK
6.rowse .. ,
..!J
Priority
~I _c~ __ -"~_~oo_c.J
tielp
Y.l~I~IIU!llll!lml,i!!tlll~
Cancel
,-. Microsoft Message Queue 3.0 Object Libr ary ------..-------.. -----..---.. ----------1
Location:
_w _ _ _ _
Language:
_____ _
C:\WINDOWS\system32V~QOA.DLL
Standard
~
_ __ _ _ , . __ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ . _ _ . _ . _ _ _ . _ _ _
i
_
_ . _ _ __ _
.l
840
Controls
!l.rowse ...
~liCrosoft
Location:
C:\WINDOWS\system32\MSCOMCTL. OCX
_; ...... _ ..... .. ....... . .. .................. . ........ _ . , ' :, ... ....... . ......... . ... _ _ . _ _ ; _ _ ................. . . h . . ....... _ _ . .. . .. .. . ......... ...................
. 0K
Cancel
_i
,t'.Pp!,'
f!~
OK
_ _H_el p
_--,
841
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.
tCm
,;;m
Mirrn,nft
W~h P"hli,hinn
!~~--------------~-
"':"Y-;"";-;:---f"1"'
''';.o:, /,
'''-''-
......,.....
w'~~~
.:
Select proiect:
Ic :\program
I[ :J~i;:;~~:~:::::)1
~eploy
Help
842
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 :
f'.ackage folder:
IC:\Program
~C :\
ell
,. =11
:. ...1
Q] MSXM Addln
Cancel
<!!ack
:3
j9c:
Network...
Ne~Folder ...
Einish
843
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'"
";:{",L;",, ~tdil
The files in the list below will be included in your package, Click
Add to Include additional files , Clear the checkbox to the left of
the file name to remove a file from the package,
FUes:
Name
Source
""
c:\Progr am Files\Microsoft Vis
0 SETUP 1.EXE
SHELLLNK.TLB
C:\WINDOWS\system32
ST6UNST.EXE
C:\Program Files\~licr osoft Vis
V86 Runtime and OLE Automation
o
o
o
o V86STKIT.DLL
Help
B.dd" .
C:\WINDOWS\system32
Cancel
< !l,ack
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.
Cab options
i r.
:2ingle cab
~;t, "lC'"
I ,;: :"
..:J
I
I____,_ _ ___~
i
Help
Cancel
< !l,ack
844
Installation title:
!MicroStation VBA Sample
Cancel
!l.ack
."
New ~rou p
Programs
MicroStation VBA Sample
i.. ... ... MicroStation VBA Sample
8"a
New ltem...
I'
I
--"'----'
e,roperties ...
e,emove
Help
Cancel
<!l.ack
t~.in i:;h
The files that have been included in the setup package must be
placed somewhere. By default, DLLs and OCX files are placed in the
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.
Choose the file you want to modify, then change the
information in the Install Location column.
Flies:
Name
Install Location
Source
MSCOfV1CTL .OCX
msstkpr~: ~~
i C: \VV I~J~()"V\I?\syst~Il1~~
$(WinSysPath)
.... ... .. .. ..
.
,
"
' ~(Win?ysPath)
$(~p'pPath~
$(WinSv.sPath)
Cancel
< !l,ack
H::::: tl~~t:?:: tP
Shared files :
Name
o Projectl.exe
<
Help
Cancel
Source
C:\Program FilesV1icrosoft Visual Studio\VB91
I.
846
~:""~~~,,,!,~
~~~........ ~~ ~
,"""11-';",""""',,\
~ '<~~"">' 1'''\/,t."-",,,,!'7~''''''''''
Files\~1icrosoft
:l.dve Report
Close
I Review I
File
Edit
View
Back
: Add, ess
847
Favorites
Tools
Help
Folders
( f
"'I,
10 RainyDayCode Addin
Ib Setup
10 Summary Inform ation
,I
Name '"
e;i.~~p'p'~;t:J
qJ Project 1. CAB
'"
~setup . exe
V; [hl SETUP. LST
'
2 '_-_ _ _ _ _
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
and the code works. When we are working in VB6, every MicroStation
Object must be implicitly set. If we declare a variable to represent the
MicroStation Application as Public in a Code Module, however, we only
need to set it once and we can use it thereafter without the need to 'set' it
again.
39
Using VB.NET
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
[B You can do this in VB.NET!
[B VBA / VB.NET Cross Reference
[B Distributing VB. NET Applications
849
850
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.
JoJ,;
Fri, 27 Jan 2006 05: 56:02 GMT My,Blogs is a collection of sample code
that shows how to easily provide programmatic access to blogs in your
applications. Chris Mayo shows how easy it is to reed and pubUsh blog
entries within Visual Basic 200S using My ,Blogs.
' !l
Visual Basic: Navigate The .NET Framewo rk And Your Projects ".
Tue, 24 Jan 2006. 16:58:48 GMT One of the biggest issues that
Open:
Create:
Project .. ,
Project...
IWeb Site.,
IWeb Site, ,,
Tue, 24 Jan 2006 18:24:04 GMT Ken Getz and Paul Sheriff show you
how to migrate your data-oriented application from Visual Basic 6,0 to
Visual Basic 2005 in Part 3 of this series.
HowDoI ... ?
What's nell'} in Visual Bastc 2005?
Create 'four First Application
r.1,:.;'
f
i
ri
~ ,[
.!
~ 11
tii{jjj
f ;li
F{[
'l!
Mon, 23 Jan 2006 23: 11:59 GMT Watch the MIX content team in action
as they talk about their plans for this new conference happening at the
Venetian hotel in Vegas.
User Interface Contro ls in Visual 8asic 6 a nd Visual Oasic 2005
Fri, 20 Jan 2006 20:08:28 GMT When upgrading Visual Basic 6
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.
Fri, 13 Jan 2006 t 7:59:25 GMT - Attend the MIX conference, a LIVE !
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
Project types:
Templates:
_._--_._-----------_._------_...
8 Visual Basic
~emplates
Windaws
II Smart Device
Starter Kits
II Other Languages
II Other Project Types
~
..vB
Windows
Application
Class library
"
Consale
Applicatian
Jill
Windaws
Web Control
Library
Cantrollibrary
Empty Project
i ~licraStatian Contral A
I
~[
Cancel
I.
2
OK
Cancel
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
Edit
View
Projett
Build
Debug
Data
Tools
I h G'J'1;',' ~ ! 3!
.
'.
-.
Window
' ~1
Community
r" ., .
IJ
4 . . . . . --
Help
~]i ,"".~
:!]! '~ ~ ~
<>]!
-. -
~ Drj~,....-.._~
"_ __
)('
,-
g-
Ii
Application
'I
Compile
ReFerences:
x II
1
.
Debug
!
___,____...___J
II
Unused References".
"
ReferenceP :CJ
1j
'I
~ __ ~I
Ty~ ~:r~,~
S.opY" l ocal
P"'th. _
COM
8.0.0, 0
True
,NET
2,0,0,0
False
C:\WINDOWS\Microsof
,,1
References
I ..
i
!
C: \ WINDOWS\Microsof
Resources
,NET
,NET
2,0,0,0
2, 0,0, 0
False
False
C:\WINDOWS\Micro,of
C: \WINDOWS\Microsof
Settings
,NET
2, 0,0, 0
Fal,e
C:\WINDOWS\Microsof
My Project
~ Form1. vb
(:\WINDOWS\Microsof --
l5iI
i
;1,'
I!~,~~,~~,,",,[W=~,,,,;=C~I~,,,--,-,-,=-,,,,,--,
;11
~~~f--
"
~================================-=--=,--=---~--It-===--=--=======I
Ready
4 Switch over to the Forml.vb tab and pin the Toolbox by clicking on
the pushpin icon at the top of the toolbox.
5
Now, drag and drop a Button from the Toolbox to the Form.
~
..... :- . "...'w,
"-~
SttJ}}IWi!lItQIY~J:9r~ ""'.
f;l h91lJfIlOll Qmtrpls '" _, ' __
11\
Pointer
(ill
Button
rn]
CheckedListBox
-"'1"W*_'"
'Vi'
','
.. ..
".
o;~
. ... 0
w "."
I!
;
o CheckBox
~ ComboBox
Nm.'l that we are in the Click event of the Button, we are going to
enter some very simple code that 'attaches' to MicroStation and
displays the Application's Caption in a MessageBox. Here is the
entire listing of code that includes this basic fun ctionality.
I VB.NET Introduction I
853
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
854
1 Debug
ffIl
Data
Tools
Window
. d MicroStation Control A
Edit
View
Favorites
Tools
Help
H
"
"
""
" "
""
"" """
......................................................... ....
..... __..._..... ;=
......=.. ~=~=""'~=~k===~==~==~. ~=_~=~~=
Ad9~~~ ro C:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\Projects\MicroStation Control A\~'icroSt
Folders
X
I--El-:ro:--V-isu- a-I S-tu-d'-,o 20-05-----\=~!
Name ""
"
Size
Type
'~[i6:t:;;,~~~::0.i~i~~~~~i~6~:~:~li::i''-1;208KBDUF~~~-~~~",--.~.-.=.
.-
28 KB
60 KB
1 KB
Application
Program Debug Database
X~'L Document
[JI
I VB.NET Introduction I
2
8S S
lI Environment
8 Projects and Solutions
General
VB Defaults
:J Text Editor
:! Windows Forms Designer
:! Device Tools
1ml.ftiititit\t:nttiitift.tt1W
.1.t.i!"t4.tm\ml.im;ft.mn#1~
[J
[CJO~~;;;~t-;~~g~\Ad;;;~-~MYDo~~-;';t~Vi~~~iSt;lo;l
-.
[J
_ ..J11 Cancel
ti.-......;;.
O;.;.
K
_':''J
I Project
,. ~1i~;oStation
C~nt;~1 P-
confi~ur a~~n
Release
, Platform
~'! Any CPU
Build
III
856
11'
t~;
~:
.'}
$ 0 00000
HEIGHT
C)
II'
J
NORTH
[l?QJ__~~:
L___
'To- W
- e-bsile- - - - - - - - - - - - - - - - - '
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,
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.
Public Class For m1
Pub l ic ExePath As Stri ng
Pu bl ic FixedHeight As Long
Pri vate Sub Form1_L oad(ByVal sender As System.Object ,
ByVal e As System .E ventArgs) Handles MyBase.Load
Dim myFile As System . IO.F i leIn f o
Dim myFo l der As New _
Sy stem. IO . Dire c to r yIn f 0 (Ap P1 i cat ion. Ex e cut a b1 ePa t h)
Dim myLstVI As ListViewItem
Dim myImg As Image
Dim myThumb As Image
ExePath = myFolder.Parent.FullName
For Each myFile In myFolder . Parent.GetFiles("*.bmp " )
myImg = Image.FromFile(myFile.FullName)
myThumb = _
myImg.GetThumbnail Image( _
ImageListl.ImageSize.Width, _
ImageList1.ImageSize.Height, _
Nothing , Nothing)
myThumb.Tag = myFile . Name . ToUpper . Replace( ". BMP ", "H )
ImageList1.Images.Add( _
myFile.Name.Replace( ". bmp " , "H ) , myThumb
myLstVI = lstvCells.Items.Add(myThumb.Tag, _
ImageList1.Images.Count - 1)
Next
End Sub
858
859
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.
860
861
False
862
JI4.
EJ~ Levels
,,0
AF6G-BldgExti
A-F8-G-BldgMisc
:0 A-G251-G-WaIlExtl
, 0 A-ZOOO-D-Dim
A-2000-G-Anno
A-ZOO1-G-lden
A-2011-G-TitI
A-2013-G -Legn
Default
. 0
Frame
j ... r::;;> links
' ...e> Object
Models
:
i(il Composite Cut Ground Floor Plan
:
cO Ground Floor Plan
$ . pt BSI300AE201-Elevations.dgn
EJ @ Levels
j .. ..
A-F44-G-SubsNich
.
t,?
.. =
=
i am
Users browse to a folder they
want to view. Each .dgn file is
loaded into the TreeView
=
control and each .dgn file is
opened in MicroStation "For
Program". Levels and Models are extracted and displayed under the
"Levels" and "Models" icons under each design file. The 3D and 2D
models are distinguished by their icons.
. .p.
:. 14
....~
'...p.
'. p.
, .~
,. ~
: 14
, .. ~
: It
, 14
' 14
. . It
BSI300AE301-S ections.dgn
BSI300AE501-Details.dgn
BSI300AE701-RCPlan.dgn
BSI300AE9-Atrium.dgn
BSI300AE9-Core.dgn
BSI300AE9-Shell.dgn
BSI300C-9-Site.dgn
BS1300G1001-CoveLdgn
BSl300Gl9-3DMasteLdgn
B513001-9-1 nteriOL dgn
BSI300S-9-Atrium.dgn
BSI300S-9-Structural.dgn
BS!30(!><-9-Sign.dgn
863
FormWindowState.Normal
LastPath
864
865
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
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,
867
when we type the name of a variable declared as a String and press the
period key, we see:
..
to.
~=
r-=
. -.~-.-------".-
i~
ser
ToLowerInvariant
v i
'\.j
.., ToUpperlnvariant
'ci nder
ByVal e .~ TrimEnd
Dim myName
''I TrimStart
myN ame =
PI
Common
: ..i
../
s)
As System. Object,
Handles B u ttoni. Click
All
IIsaBox (mvName .
As we can see here, we can use the ToU ppe r method of a String Object
instead of using UCas e (see below).
Ucase( my Name) ' VB6 and VBA
myString.ToUpper VB . NET
To Upper is a method of the String Object. And how about the String
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:
... 1 of 3 ~ Open (mode As 5ystem.IO.FileMode) As System.IO,FileStream
: mode: A System,IO.Filer~ode constant specifying the mode (for example, Open or Append ) in which to open the file,
... 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,
868
In VB.NET:
MsgBox("This is a test.")
869
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 SendMa i 1A( )
870
"yoursmtpserver.com "
"you@bentley.com", _
"Mi croStat i on VBA" , "Email i ng using . NET is easy ." )
End Sub
=
The first example, SendMa i 1A shows us that with only three lines of code,
we can send an e-mail. Se ndM ai 1B does things a little differently.
Se ndMa i 1B adds an Attachment to the e-mail that is being sent. Of
course, the SMTP.Host, From, and To fields in each of these examples
need to be modified to reflect legitimate e-mail server and mailbox
settings.
871
c: \lIicroStation
C: \IUcroStation
:\Hi croStation
:\lIicroStacion
: \ Ui croScation
:\MicroStation
:\Micr oStat ion
: \ Micr oStati on
VBA\cd material
VE A\ docs
VBA\Documents
VBA\Fonts
VBi\. \ from mark
VBA \ FTP i n VB Doc Net
VBA\pics
VBA\Source Code
:\HicroStation
: \lIicroStation
:\HicroStation
: \liicroStation
:\Hicr oS tation
: \HicroStation
: \HicroStation
:\HicroStation
:\HicroStation
C: \HicroStation
VBA\USGS
VBA \ VB6
VBA\FTP in
VBA \ PTP in
VBA \ FTP in
VBA \ FTP in
VBA\FTP in
VBA\FTP in
VBA\FTP in
VBA\FTP in
VB Doe ?-let\CS
VB Dot Net \ VB
VB
VB
VB
VB
VB
VB
Dot
Dot
Dot
Dot
Dot
Dot
Net\VB\FtpSample
Net \ VB\ FtpSample\bin
l~et\VB\FtpS ....ple\obj
Net\VB\FtpSample\obj\Debuq
Net\VB\FtpSample\obj\Debuq\TempPE
Ilet\CS\FTPSample
872
VBA\BatchProcessinq\File R.dgn
VBA\BatchProcessinq\BatchD\File W.dgn
VBA\ BatchProcessing\BatchD \ File X.dgn
VBA\BatchProcessing\BatchD\File Y.dgn
VBA\BatchProcessing\BatchD\File Z.dgn
VBA\BatchProcessing\BatchC\File U.dgn
VBA\BatchProcessing\BatchC\File V.dgn
VBA\BatchProcessing\BatchB\File R.dgn
VBA\BatchProcessing\BatchB\File S.dgn
VBA\BatchProcessing\BatchB\File T.dgn
VBA\BatchProcessing\BatchA\Pile F.dgn
VBA\BstchProcessing\BatchA\File G.dgn
VBA\BatchProcessing\Batc:hA,\File H. dgn
VBA \BatchProcessing\BatchA\ File J. dgn
VBA\BatchProcessing\BatchA\Batc:hA-3\File
VBA\BatchProcessing\BatchA\BatchA-3\File
VBA\BatchProcessinq\Batc:hA\BatchA-2\File
VBA\ BatchPr ocess ing\BatchA\BatchA- 2\ File
VBA\BatchProcessing\ BatchA\BatchA-l\File
VBA\BatchProcess i nq\Bat chA\Batc:hA- l \Fi l e
P.dqn
Q.dgn
M.dgn
N.d~l
K . dgn
L.dgn
!f
tYl
c>}
873
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:
Declare Function ExtractIcon Li b "shel13Z . dll " Alias
"ExtractIconA " (ByVal hInst As Integer . _
ByVal lps zExe Fi leName As Str i ng . _
ByVal nI con I nd ex As Integer) As I nteger
Pub l ic Declare Function FindExecutable Lib "shel13Z.dll " Alias
"FindExecutab l eA" ( ByVal lpF i le As Stri ng. _
By Val l pD ir ecto ry As String . ByVa l l pRes ult As Str in g) As Long
The first call, Extr ac tI con extracts a specific icon from an .exe or .dll
file. Fin dEx ecutab le allows us to specify a file name and it returns the
path to the program registered to open the file. We will see these used in
a little while.
Let's look at the main Procedure that kicks things off.
1
874
Now, for the Functions I con FromExtens i on, I conFromFi 1e, and
GetDefWi nI can. Each of these functions use another function,
I ca nFromV a1ue. which parses the results of the Def au It I con value when it
is retrieved from the Registry.
Function IconFromExtension(ByVal FileExtension As String)_
As Bitmap
Dim MyKey As Microsoft .W in32 . RegistryKey
Dim MyDefaultKey As Microsoft.Win32.RegistryKey
Dim myCR As Microsoft.Win32.RegistryKey
Dim myDefaultlcon As Microsoft.Win32.RegistryKey
Dim DefVal ue As String
myCR = Microsoft .Wi n32 . Regis t ry . ClassesRoot
MyKey = myCR.OpenSub Key(Fi l eExtension)
875
876
dgn ,bmp
dgna ,bmp
doc.bmp
doca,bmp
gz ,bmp
gza,bmp
htm,bmp
htma ,bmp
When this program is run , Bitmap files are created for each unique file
extension found in the specified folder.
877
VB.NET ApPLICATIONS
1 Debug
Data
Tools
Win
Publ~~ V.B~TOVS.NET ~
_______
You may publish the application to a web site, FTP server, or file path.
Examples :
Disk path:
c:\deploy\myapplication
File share:
FTP server:
\\server\myapplication
ftp:/Iftp .microsoft.comimyapplication
Web site:
http://www.microsoft .comimyapplication
Next
> .~ [
Finish
II
Cancel
878
-<"'~g""
3"~'~
Publish Wizard
,,''''''>~''~.
'
",
__ ,
"""'''~.~'''',_,v->"".~
"
'
"
-'
_~_~"'~'<_"'''T'
, ' , :"
__
~.;Y''fi'Y7
~~
"
In our example, we will create a Setup that is to be run from CDROM or DVD-ROM.
,0
< Previous
Ii
Next>
Finish
I[
Cancel
879
Ready to Publish!
The wizard will now publish the application based on your choices .
-----_._----_.
- - - -.- . - - - - - - -
< Previous
Cancel
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.
~~:~:~:~:p.:;:~:~:~:::1
Si.2: _ ..:ype_ ..
File Folder
422 KB Application
6 KB Application Manifest
6 KB Application Manifest
880
Additional Sources
GENERAL VBA RESOURCES
http://msdn.microsoft.com/vba
VBA Overview, Whitepapers, etc.
http://bentleyinstitute.bentley.com/catalog.aspx?discipline= 10
Programming Classes offered by Bentley
Mastering Microsoft VBA; ISBN: 0782144365
VBA Developer's Handbook; ISBN: 0782129781
Google, Yahoo, or other Internet Search for "VBA" or "Visual Basic for
Applications"
http://discussion.bentley.com
Look for the bentley.microstation.v8xm.vba discussion group.
VB and VBA in a Nutshell; ISBN: 1565923588
SQL STATEMENTS
http://msdn.microsoft.com/library/en-us/tsqlreflts sases 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
Programmer); ISBN: 0764571982
Reference
MATHCAD
www.mathcad.com
XML
XML in a Nutshell, Third Edition, ISBN: 0596007647
XML Programming Bible, ISBN: 0764538292
(Programmer
to
Index
& (ampersand), 100
, (apostrophe), 6
* (asterisk symbol), 105-106,736
\ backslash symbol, 106
1\ (carat symbol), 106
: (colon symbol), 291
I (forward slash), 106
- minus symbol, 105
I (pipe symbol), 729
+ (plus symbol), 104
.II (selectNodes), 592
A
About Microsoft Visual Basic, 21
Abs function, 110-1 11
Absolute Value, 110-111
Accept event, 399
Access, Microsoft, 554-557
accessors, 193
Action parameter, 548
active design file, 95
Acti veModelReference, 417
ActiveSheet, 692-694
ActiveX Automation, 769, 784, 787,
808
883
884
I Index I
Alias, the, 650
alignment, 362
buttons, 367-368
creating, 735
horizontal, 365-368
vertical, 368-370
ApplicationObjectConnector, 222
applications
building in VB.NET, 854-855
communicating with other, 784
compiling in VB6, 838
compiling Microsoft Visual Studio
2005,854
compiling VB6, 837-838
distributing VB6, 839
distributing VBA, 501-503
distributing VB.NET, 877
ArcElement, 75-76
arcs, creating, 301
ArcTangent, 110
arrays, 60, 77
changing the size of, 416
dynamic, 371-372, 447
returning, in a function code, 60
storing file extensions to, 446
B
backslash symbol (\), 106, 190-191
.bas (Module) files, 16
BaseElement, 573-574
BasePoint click, 363- 364
batch processing, 599-621
Beep function, 128,650
Before Detach event, 524, 526
BeforeActivate event, 527-529
BeforeAttach event, 525
BeginUndoRedo Event, 537-538
"Bentley MicroStation DON #.#
Object Library, 788, 795, 817,
851
Bentley website help files, 41-42, 44
binding, 690-691, 785-787
Bitmap files, 859, 873-876
Bookmarks, 18
Boolean data type, 72
Boolean value, 113-114
BorderStyle property, of Image
Control, 167
Break,20
Break point, 357, 465
Browse button, 384
bubble sorting, 372-373, 377
bubble sorting function, 88-90
"B uilding" project, 571, 854-855
I Index I
buttons
alignment, 366- 368
Browse, 384
Cancel, 17 1, 443
Change Current Selection, 357-358
Close, 358-359
Command,164
creating, 798-802
Draw In MicroStation, 737-738
Pick, 172, 173
Run Macro, 4
seed file selection, 442
Select, 356-3 57
Spin, 167
Step Into, 12
Toggle, 163
unassigned cursor, 337
C
.CAB files, 847
Cad Input Queue, 334-340, 364
CadlnputMessage, 334
list of properties and methods in, 227228
calendar, 669
Call Stack window, 18, 27
calling, 57-58
class modules, 394-395
PointString element, 417
variables, 421
885
cells
adding to library, 306-307
changing column designation in Excel,
695
changing fo rm ula in, 701
changing values in, 701
creating, 304-307
declarations, 305
finding specific Excel, 694-695
selecting, 346-347
class files, 16
Class Module windows, 19, 30
class modules, 54, 394, 445
adding, 52-54
calling up, 394-395
clsTimeTrack, 491 - 493
interfaces and, 392
lifecycle, 395- 396
MDL Applications and, 387-388
886
I Index I
Class_Initialize event, 493
Class_Terminate event, 493
ClassComplete property, 424-425
classes, 52, 67, 784. see also objects
adding, 524
default file name of, 394
implementing, 52-53
terminating declared, 396
clsTimeTrack,491-493
cmdCancel_Click, 171
code, 18,52-54,516
controlling execution of, 26, l35
repeating, l37-l38
use of, within VBA Project Manager, 4,
6
viewing, 29- 30
CommandState.CommandN arne
property, 541, 548
comments, 6, 47
compatibility, setting, 834
compiling
ActiveX Controls, 830-832
applications in VB6, 838
applications in VB.NET, 854
Complete Word, 18
complexity, degrees of, 368
Compressed (zipped) Folders, 507
Computer name function, 613-615
Configuration Manager, 854-855
Connection Object, 715, 719-722
Connection Strings, 563, 716, 722723
constants, 78, 100
ADO, 746-749
cursor type, 725
List, 17
lock type, 725-726
message boxes, 118-120
QueryClose,360-361
vbProperCase, 85
contents tab, 35
control events, 154- 155
control names, 377
control placement, 363
control properties, 377
controls, 20,29, 151,353-355
ActiveX, 669-670
adding, 168
creating, 822-826
initializing, 829
properties for ComboBoxes, 160-161
properties for ListBox, 161
properties for TextBox, 159
registering, 830-831
standard, 27
in Toolbox, 152,668
TreeView,822-826
use offrame with, 164
I Index I
coordinates, 35 1
CopyFileToZipFile procedure, 508509
Cos (cosine) function, 107-108
counting
characters, 90-91
elements, 374
Create button, 13
Create3dLines, 291-294
CreateArcElement, 301-303
CreateCellElement, 305-307
CreateCircle, 298-300
CreateDatabaseLink, 564-565
CreateDesignFile,307-309
CreateDia1og, 459
CreateEllipseElement, 297-298,
300-301
CreateLineElement, 289-295
CreateObject, 691 , 789, 790
CreatePolygon, 296-297
CreateShapeElement, 295- 296
CreateTextElement, 303-304
cursor buttons, unassigned, 337
cursor movement, 426
cursor type constants, 725
Custom Class Modules , 474-478
Custom file Properties, 686-687
Custom tab, 685
Custom types, 282-283
Cut, 17
o
data, security issues with creating,
309
DataBaseLink object, 552
databases
connectingt~557-561, 7 19
887
DateAdd function, 122-123
DateDif function, 123
DDE (Dynamic Date Exchange),
784
Debug folder, 854
debug menu, 19
debug mode, 12
debug toolbar, 22
debug window. see immediate
window
De-bug.print, 85
declaration, 189
of API calls, 649-650
area,66,282-283,355
default setting, 67
DIM,66
form functions, 431
private, 66
public, 66-67
of types, 650- 651
of variables, 66, 70, 76
of variables in Mathcad, 762
Design Mode, 20
Design Time, setting properties at,
152
DesignFile Object, 74, 228-230
DesignFile property, 522-523
DON Browser application, 862-865
DON files, 74, 446
compressing into Zip file, 507
creating levels in, 796-802
numbering within zip files, 510
opening multiple, 484-485
searching for, 382
888
I Index I
dialog functions, 432-444
DialogOpenfile command, 352-353
Dictionary Object, 676-677
Digital Signature, 20
DIM statements, 6, 66
Dir function, 125-127, 603
directories, 124-125
displaying, 23
attachments, 381-382
Excel files, 437
models and levels in Active Design
File, 822-826
more than one file type, 438
one file type at a time, 437
RSS files, 743-744
text as code executes, 26
distribution, 374-375
division, 106
division points, 422-424
DivPts property, 422-424
DLLs, 20, 431, 670
creating Active X, 832
E
early binding, 690, 691, 785-787
edit button, 12
edit menu, 17
edit toolbar, 22
Element objects, 230-236
ElementChanged event, 539-540
ElementEnumerator, 236
elements, 369-370
deleting, 547-548
displaying DatabaseLink in message
box, 565
finding specific, 404-406
ID property of, 577-578
linking to database records, 564
modi~ng,539-542
EllipseElement,75
ellipses, creating, 300-301, 410-412
e-mail, sending, 619-620, 680-681
in VB.NET, 870
I Index I
enumerations, 243-245
ErrorType, 639
for horizontal alignment of text, 366
list of, 245-277
MCRegionType,765-766
MsdACSType, 245
MsdAddAttachmentFlags, 245
MsdAngleAccuracy, 245
MsdAngleFormat, 245
MsdAngleMode, 246
MsdAttachMode, 246
MsdBsplineCurveOffsetCuspType,
246
MsdBsplineCurveType, 246
MsdBsplineParametrizationType, 246
MsdBsplineSurfaceDirection, 246
MsdBsplineSurfaceType, 246- 247
MsdCadlnputType, 247
MsdCellType, 247
MsdChangePropagation, 247
MsdChangeTrackAction, 538-539
MsdCommanResult, 248
MsdConversionMode, 248
MsdCoordinateAccuracy, 248-249
MsdCoordinateFormat, 249
MsdCopyContextLevelOption, 249
MsdCopyViewPort, 249
MsdDatabaseLinkage, 249
MsdDataEntryRegionJ ustification, 249
MsdDesignFile Format, 250
MsdDevelopableElementOutputType,
250
MsdDialogBoxResult, 250
MsdDimAccuracy, 250- 251
MsdDimAlignment, 251
MsdDimAlternateThresholdCompani
on, 251
MsdDimAngleMeasure,251
MsdDimBallAndChainAlignment, 251
MsdDimBallAndChainChainType,
252
MsdDimCustomSymbol, 252
MsdDimDMSPrecisionMode, 252
MsdDimLabelLineFormat, 252
MsdDimMLNoteFrameType,252
MsdDimMLNoteJustification,252
MsdDimNoteHorizontalAttachment,
252-253
MsdDimNoteLeaderType, 253
889
MsdDimNoteTextRotation, 253
MsdDimNote VerticalAttachment, 253
MsdDimNote VerticalJ ustification, 253
MsdDimPlacementTextPosition, 253
MsdDimRadialMode, 253
MsdD imS tackedF ractio nalAlignm en t,
254
MsdDimStackedFractionType, 254
MsdDimStyleProp, 254-260
MsdDimSuperscriptMode, 260
MsdDimSymbolType, 260
MsdDimTerminatorArrowhead,260
MsdDimTerminatorMode, 260
MsdDimTerminatorType, 260-261
MsdDimTextField,261
MsdDimTextFormat, 261
MsdDimTextFrameType,261
MsdDimTextJustification,261
MsdDimTextLocation,261
MsdDimTextOrientation, 262
MsdDimThousandOpts,262
MsdDimToleranceType, 262
MsdDimType, 262-263
MsdDim ValueAngleFormat, 263
MsdDim ValueAnglePrecision, 263
MsdDim VerticalTextOptions, 263
MsdDrawingMode, 263
MsdElementCachePurpose,263
MsdElementClass,263-264
MsdElementSubtype, 264
MsdElementType, 264-265
msdElementType,312-313
MsdError,265-27 1
MsdFileAccessMode,271
MsdFillMode,2 71
MsdFontType,271
MsdGeoReferenceSisterFileType, 271
MsdGlobalLineStyleScale, 27 1
MsdLevelChangeType, 271- 272
MsdLevelElementAccess,272
MsdLimits,272
MsdMeasurementBase, 272
MsdMeasurementSystem, 272
MsdMemberTraverseType, 272
MsdMessageCenterPriority,273
MsdModelChangeType, 273
MsdModelType, 273
MsdNestOverrides, 273
MsdNewLevelDisplay, 274
890
I Index I
MsdRasterBlockType,274
MsdRasterDisplayOrderCommand,
274
MsdRasterDisplayPriorityPlane,274
MsdRasterModificationType,274
MsdRasterWorldFile,274
MsdReferenceSystem, 274-275
MsdRenderingMode,275
MsdStandardsChecker ReplaceChoice,
275
MsdStandardsCheckerReplaceOptions,
275
MsdStatusBarArea,275
MsdTagType, 275
MsdTangentElementOutputType,276
MsdTangentInterpolationType, 276
MsdTextDirection,276
MsdTextJustification, 276
MsdTextNodeLineSpacingType,276
MsdV7 Action, 276
MsdViews,277
MsdXDatumType,277
I Index I
examples folder, 39
Excel, 437, 793-794
Add-In fil es, 803-805
connecting to, 689-690
customizing, 798
as databases, 749-754
MicroStation, 793-795
opening, 753
starting or creating new instance of,
691
XML file exported from, 593-594
ExtCount, 447-448
"Extended Property", 749-754
Extensible MarkupLanguage. see
XML
ExtractIcon, 873
F
favori tes tab, 37-38
feedback,329-331,375-376
capturing user, 359
891
File System Obj ect, 484, 576,
675-678
FileCreate function, 458-459
Fi1eDateTime function, 124
FileLen function, 124
Fi1eOpen function, 432
files
adding to Setup package, 843
ASCII Text, 19
batch processing of all folder, 603-604
cataloging, using Dictionary Object,
679
filtering, 31 7-318
finding, 3
identifying, 665- 666
loading, 2
processing, in folders and subfolders,
607
reading in VBA, 868
reading in VB.NET, 868-869
registering, 837, 841
saving as Bitmap, 873-874
scanning, 311 - 314
searching, 311
sending, to CD writer, 512-513
types of, 604
user interface for, 608-613
writing in VBA, 869
writing in VB.NET, 869
zip, 507-508
FilesInFoldersmethod, 385-386
FileSystemObject, 385
FillMode parameter, 296
filtering, 3l7-318, 404-406
Find, 17
Find method, 727-728
FindExecutable, 656-657, 873
Fix function, 112
floating point, 71
fmStyleDropDownList, 169
FolderIn parameter, 607
fo lders, 23
processing, 606-608
root, 382, 675
selecting, 382
traversing, 870-871
892
I Index I
For ... Next statement, 135-137
For Append, 131 , 483
For Each ... Next statement, 141 , 472
form files , 16
Form Load event, 817
Form1 (VB6), 810
Format function, 100
format menu, 19
FormatCurrency function, 98
FormatDateTime function, 99
FormatNumber function , 98-99
forms, 49, 353
creating with VB6, 809-816
displaying as modeless, 361
public, 67
window, 28-29
forward slash (I) , 106
G
geometry, creating MicroStation,
771
GetAllRegions function, 773- 774
GetAllSettings function, 129- 130
GetComputerName, 613-614, 653
GetDiskFreeSpace, 657
GetDriveType, 652-653
GetEvals, 774-775
GetExts, 447, 450
GetInput method, 335
GetLogical Drives, 652
GetObject, 689- 690, 788- 789, 818819
GetSelectedCount, 374
GetSetting function, 128
GetString method, 728
GetSystemMetrics, 658-659
GetTags, 573
GetThreeVals, 65
GetTickCount, 659- 660
Getting All Files, 871-872
GetType functionality, 544-547
GetUserName, 660
GetValue, 759-760, 772-773
GetVersionEx, 653-655
GetWindows Directory, 660-66 1
graphical elements, 289
Graphical User Interfaces (GUIs), 7,
49, 96
grid, 20
group collection method, 324- 325
grouping, 474-478
groups, creating named, 323
H
hardcoding, 47, 351
headers , 178
height property, 157
help files
Bentley website, 41-42, 44
Object Browser, 190- 191
Visual Basic, 21, 34
I Index I
IModelChange events, 527-530
Implements (keyword), 392
import file, 16
Import Image MDL application,
387-388
Inc1udeOnlyWithin Range method,
326
Indent, 17
Index attribute, 595-596
index tab, 36
information
retrieving from a web site, 617-618,
741-742
storing, 615-616
J
Join function, 95
K
Key Ascii parameter, 170, 365
KeyDown event, 160
893
Key-In dialog box, 352
Keyin event, 4 16
Keyin window, 337
key-ins, 417
KeyPress Event, 96, 155, 160, 169170, 364-365
Keys, using, 473-474
KeyUp event, 160
keywords, 78
Kill function, 127
L
Label control, 158
late binding, 690, 785-787
Lcase function, 84-85
LCE_DistanceText, 402-404
LCE_Text, 397-398
Left function, 90
Left property, 156
Len (length) function, 90
Level Mapping file, 488-489
levels, 74-75 , 377, 531
adding to a collection, 473
batch processing, 600
CheckLevei function for, 704-706
creating in .dgn file, 796-802
equalizing, 738-740
list of properties and methods in, 237238
modifying, 548-549
894
I Index I
load project button, 3
Locals Window, 18, 26
LocateCriteria object, 404-406
LocateFailed event, 399
LocateFilter event, 398, 400
LocateReset event, 399
Lock proj ect property, 500, 797
lock type constants, 725-726
log files, 613- 614
LogonUser, 661
LogToWeb, 617
Long number, 70- 71,111 - 112
lower case function, 84-85
M
macros, 3- 5, 20
recording, 348- 351
running, 793-794
running a MVBA, 5
running Excel, 797-805
using Mathcad, 757- 759
methods
Add Note, 736-737
AddItem, 161, 168-169
AddNew,729-730
AlignSelected,366-368
application obj ect, 189
collection, 316-324
creating new in Class m odule, 459
DrawLine, 466
DrawLinePerp, 466-467
Execute, 719
FileslnFolders, 385-386
Find, 727-728
GetInput, 335
GetString, 728
group collection, 324-325
IncludeOnlyWithin Range, 326
interfaces and, 392
MoveFirst,727
multi-criteria collection, 321 - 324
New, 692
OpenDialog, 446
OpenSchema, 746, 751
overloaded, 867-868
Pages.Add,165
Pages. Count, 165
ScanCriteria collection, 316-322
Show, 183-184
ShowError, 332
ToUpper,867
Update, 729-730
I Index I
MicrosoftSpeechObjectLibrary, 679
MicrQStation, 18
MicroStation
attaching to project in Visual Studio
2005,852-853
controlling with VB6, 81 6
creating new instances of, 790-791
Excel versus, 793-795
module files, 16
modules , 45-46, 67
insert, 19
opening, 30
895
N
Name property, 189
named group search, 323
naming
controls, 155
conventions, 79, 156,355
variables, 78-79
o
Object, view menu, 18
Object Browser, 18,24,42-44, 149,
757
description of, 188- 190
displaying Members of the Object,
671-672
opening Microsoft VBA Help in, 40
896
I Index I
opening files, 386, 438
OpenSchema method, 746, 751
operating system, determining, 653655
OptionButtons, 162-163
option explicit, 67, 80-81
Options, 20
Order By statement (SQL), 732-733
Order of Operations, 116
Outdent, 17
Output, 483
overloaded methods, 867-868
p
Pages.Add method, 165
Pages.Count method, 165
Pan operations, 183
ParamArray, 57-58
Parameter Info, 17
parameters, 47-49,57,65,68
"parcel" table, 553
parenthesis, using, 853
in VB.NET, 868
passwords
protecting, 498-500
requesting from user, 661-662
Paste, 17
Path property, 189
paths, 451-452,656-657
Pause Recording Macro, 11
PCE_CircTest, 410--412
PCE_LineTest, 407-408, 417-420,
424-426
PCE_PointStringTest, 414-416
PCE_PolyTest, 412-414
PCE_RecTest, 409
PCE_TestLine, 420--424
personalizing help fi les, 38
pFileExts, 447-450
Pi function, 59
Pick button, 172, 173, 363
PictureBox control, 873
pipe symbol (I), 729
Place Block, 341-343, 350
Place Line command, 341-343
PlaySound function, 662-663
plus symbol (+), 104
Point List Reader, 174-177
I Index I
properties, 20, 152
application object, 189
Custom file, 686-687
implementing, for classes, 52
viewing, of variables, 192
writing, 682-683
R
R1C1 reference style, 696-697
radians, 107-108
"Radius" parameter, 56
RaiseEvent statement, 469
RAND function, 704-705
random number, function to
generate, 115
range addresses, 697-698
Range Collection, 695
reading
ASCII Text files, 130-131, 132-135,
676-677
in VB A, 868
in VB.NET, 868-869
from the Windows Registry, 616
XML files, 587-594
897
References, 20, 500-501, 785, 840
adding, 484
adding, to DLLs, 670
adding, to Microsoft Excel Object
Library, 690
"Bentley MicroStation DGN #.# Object
Library, 788, 795,817,851
DSOFile, 681-682
Mathcad, 756
Microsoft ADO Ext. 2.8 for DDL and
Security, 554
Microsoft Internet Controls, 617, 787
898
I Index I
running a project automatically,
494-495
run-time, setting properties at, 152154
S
Save button, 22
SaveAs functionality, 510- 517
SaveSetting function, 128
savmg
class modules into VBA Project, 461 462
projects with CreateDialog method,
459
SHGetFileInfo, 665
shortcuts, 844
Show method, 183- 184
ShowCommand,339-340
Show Error method, 332
ShowEvents procedure, 287
ShowPrompt, 339-340, 359- 360
ShowTempMessage, 331
Sin (sine) function, 107-108
Sleep function, 656
SND_ASYNC flag, 663-664
sorting
bubble, 88-90, 372-373, 377
in SQL, 732-733
text, 87-90
sounds, 663-664
Space function, 435
spaces, removing, 86
spacing, text, 368, 375- 376
SpacingXIn formulas, 779
SpacingYIn formulas, 779
speech capabilities, 679
Spin Buttons, 166-167
Split function, 95
SQL Query Builder, 561, 565-566
SQL Select Statements, 562, 730731
Sqr (square root) function, 107
squares function, 106
Standard EXE, 810, 839
Standard toolbar, 22
Standard VBA variable types, 70
standards
checking for, 634
cross-company, 485-487
maintaining, 479
I Index I
storing
confidential information, 449
information, 615-616
point selections, 366
settings, 387, 632
T
Tab Order, 18
Tab strips, 164
tab width, 20
tab-delimited files, 483
Tablndex property, 157
tablename field, 552
tables, creating, 555-563
TabStop property, 157
Tag property, 158
tags, 571-578
extracting information, 707- 711
TagSetName, 573
Tagsets, 575-576
TakeFocusOn Click property, 164
Tan (tangent) function, 107-110
temporary message, 331
temporary storage location, 513
terminology, 32
"Test Connection" message box,
560-561
TestCadlnputN, 352
899
testing
ActiveX DLL, 836
clsTimeTrack, 493
default path, 451-452
DrawLinePerp method, 467
file extensions, 447-450
startpoint and endpoint, 464
TestMatchProperties, 361
text alignment, 362
text boxes, 37-38,364
text elements
capitalizing, 397-398, 400-401
comparing, 87
creating, 303
determining number of, 369-370
Tools Menu, 20
Top property, 156
ToUpper method, 867
tracking, 615
transaction logs, 619-620
translating standards, 485-487
traversing a folder and subfolder,
870-871
Trim function, 86
Try function, 861
.txt files, 445
Type Libraries, 20, 785
types, 279-283
API, 650-651
available in MicroStation VBA, 281 282
MicroStation-specific variable, 73
returning, 62-63
standard VBA variable, 70-73
900
I Index I
variables, 6, 66, 68
U
UCase function , 84
UDL files, 557-560, 563,715-719
connecting to Excel file, 750-751
opening a connection using, 722-723
RSS and, 741
V
Val function, 113
validating path, default, 451-452
Value property, 162, 163, 165, 166,
167
values, 63
assigning, 76-77
constant, 78
retrieving cell, in Excel, 694-695
retrieving in Mathcad, 773
returning function, 872
tag, 572
VBA editor, 12
VBA Files From Levels form , 380381
VBA IDE, 15-30
VBA Project Manager, 3-5, 7, 9-13
elements of, 10
VBAPM,3-5
vbCr constant, 100
VB.NET,850
vbProperCase, 85
vbTab constant, 101
vertical order, 369-371
View Code, 29-30
View menu, 18
visible property, 157, 164
Visual SQL Query Builder, 557, 562
Visual Studio 2005, 850
voice capabilities, 679
I Index I
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, 382384,649-650
Windows Registry, 615-616, 632633,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, 595597
Z
zip files, 507, 508
Zoom operations, 182-184
901
902
I Index I
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.