Sie sind auf Seite 1von 941

Learning

Microstation VBA

Jerry Winters
LEARNINGMICROSTATION
VBA
First Edition

Copyright 0 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 does 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
yww.bentlev.com

Printed in the U.S.A.


Introduction

Learning Microstation VBA provides an in-depth tour of one of


Microstations 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 VBA 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 Menu and menu items

Function Object
F u n c t i onIndex Variable

Keyboard key

xvii
xviii I Introduction I

ACCOMPANYINGCD-ROM
The accompanying CD includes all source code referenced in each
chapter of the book. The CD also includes procedures, and addenda to
the book as well as a comprehensive Object Model listing and other
example files such as V8 DGN files, Microsoft Excel spreadsheets,
Microsoft Access databases, and more.

MYSELECT CD
Bentley SELECT Subscribers can order the supporting files through the
MySELECT CD program. MySELECT CD allows you to select the
Bentley software or documents you need and have a CD delivered to
your door.
To become a Bentley SELECT Subscriber, go to http://1Yww.selectservices.
bentley.com. Bentley SELECT is a subscription program that features
product upgrades and updates.

ABOUTTHE AUTHOR
Jerry Winters began his CAD career as many have, at the bottom of the
totem pole, drafting eight hours a day. It didn't take long for him to
discover that in many situations, the computer could complete repetitive
tasks much faster than he could. So, he began writing programs that not
only simplified the drawing creation process but significantly decreased
the amount of time needed to create drawings. Rather than wasting the
time saved by his programming efforts, Jerry used the new found time
to write more programs until he stopped 'using' CAD software and
began 'customizing' CAD software on a full-time basis. So, for the past
15 years, Jerry Winters has been customizing CAD software and
teaching others to do the same.
Whether it's on stage or in the written word, Jerry brings occasionally
complex programming topics down to the level of the average CAD user
(in part because he considers himself an average CAD user). His
extensive knowledge of Visual Basic programming is complimented
with Active Server Page development, database programming expertise,
and the occasional creation of Java applets for graphically-rich web-
based development.
I Acknowledgments I xix

This is his first book on customizing Microstation with VBA and he


experienced one difficulty throughout the entire book. There is just so
much that can be done in Microstations VBA environment, it is
difficult to know what to include and what to shelf for a later date.
Jerry and his wife Candice are the parents of six children. They live in
Lake Point, Utah, where they raise their children and their children raise
chickens.

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 b o x , Maureen Rhoads, and Christopher Rogers, without whom
this book would have never gotten off the ground.
Furthermore, I would like to thank the Bentley Institute for affording
me the opportunity to write about Microstations implementation of
VBA. I hope the lessons learned in this book will be as rewarding to the
reader as they have been for me.
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

The VBA Project Manager ............................... 2.9


VBA Project Manager Functionality ............................. 2.10
Macros Dialog Box ............................................ 2.12
Review ....................................................... 2-13

The VBA IDE .......................................... 3-15


Menus ....................................................... 3-16
File Menu ................................................ 3.16
Edit Menu ............................................... 3.17
ViewMenu ............................................... 3-18
InsertMenu .............................................. 3-19
FormatMenu ............................................. 3-19
Debug Menu ............................................. 3.19
RunMenu ............................................... 3-20
Tools Menu .............................................. 3.20
Add-Ins Menu ............................................ 3.20
Window Menu ........................................... 3.21

iii
iv I Contents I
Help Menu ............................................... 3.21
Toolbars ..................................................... 3.22
Standard toolbar .......................................... 3-22
Edit toolbar .............................................. 3.22
Debug toolbar ............................................ 3.22
UserForm 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

Finding Help ......................................... 4.31


Terminology ................................................. 4.32
Help Files .................................................... 4.34
Contents tab .............................................. 4.35
Index tab ................................................. 4.36
Search tab ................................................ 4.37
Favorites tab .............................................. 4.37
Microstation VBA Help File ................................ 4.39
The Net ...................................................... 4.40
The Object Browser ........................................... 4.42
Review ...................................................... 4-44

Modules. Forms. and Class Modules .................... 5.45


Modules ..................................................... 5.45
Forms ....................................................... 5-49
Classes ...................................................... 5.52
Procedures and Functions ...................................... 5.55
Returning an Array ........................................ 5.60
Returning 'Types' ......................................... 5.62
Returning Objects ......................................... 5.63
ByVal and ByRef .......................................... 5.64
Declaring Variables ....................................... 5-66
Option Explicit ........................................... 5.67
Review ...................................................... 5-67
V

Variables ............................................
Standard VBA Variable Types ..................................
6-69
6.70
Integer ................................................... 6-70
Long .................................................... 6-70
Double .................................................. 6.71
Boolean .................................................. 6.72
Date ..................................................... 6-72
String .................................................... 6.72
Object ................................................... 6.72
Variant .................................................. 6-73
Microstation-Specific Variable Types ............................ 6.73
Application .............................................. 6.73
DesignFile................................................ 6.74
ModelReference .......................................... 6.74
Level .................................................... 6.74
LineElement.............................................. 6.75
EllipseElement ............................................ 6.75
ArcElement .............................................. 6.75
TextElement .............................................. 6.76
Assigning Values and Setting Objects ............................ 6.76
Arrays ....................................................... 6.77
Constants .................................................... 6-78
Variable Names ............................................... 6.78
Case Sensitivity ........................................... 6.80
Option Explicit ............................................... 6.80
Using Variables ............................................... 6.81
Review ....................................................... 6.82

Working With Text ................................... 7-83


VBA String Functions ......................................... 7.84
UCase ................................................... 7.84
LCase .................................................... 7.84
StrConv .................................................. 7.85
WeekDayName, WeekDayNumber .......................... 7.85
MonthName ............................................. 7.86
LTrim, RTrim, Trim ....................................... 7.86
StrComp ................................................. 7.87
Len ...................................................... 7.90
Left ..................................................... 7.90
Right .................................................... 7.90
Mid ..................................................... 7.91
Replace .................................................. 7.92
InStr .................................................... 7.92
InStrRev ................................................. 7-94
vi I Contents I
Split and Join ............................................. 7.95
Asc and Chr .............................................. 7.96
FormatCurrency .......................................... 7.98
FormatNumber ........................................... 7.98
FormatDateTime .......................................... 7.99
Format ................................................. 7.100
& ...................................................... 7.100
vbCr .................................................... 7.100
vbTab .................................................. 7.101
Review...................................................... 7-101

Working With Numbers .............................. 8-103


Numeric Functions ........................................... 8.103
Addition ................................................ 8.104
........................................................ 8-105
Subtraction .............................................. 8.105
Multiplication ........................................... 8.105
Division ................................................ 8-106
Squares and Exponents ................................... 8.106
SquareRoot ............................................. 8-107
Sine, Cosine, Tangent ..................................... 8.107
Arc Tangent ............................................. 8.110
Absolute Value .......................................... 8.110
Convert to Integer, to Long, to Double, and Value ............ 8.111
CLng ................................................... 8.111
Fix ..................................................... 8.112
CDbl ................................................... 8.112
Val ..................................................... 8.113
IsNumeric .............................................. 8. 113
Round .................................................. 8.114
Mod .Find the Remainder ................................ 8.114
Sgn .Show me a sign ..................................... 8.115
Rnd and Randomize ...................................... 8. 115
Order of Operations ...................................... 8.116
Review...................................................... 8.116

Standard VBA Calls ..................................


MessageBoxes ...............................................
9-1 17
9-117
InputBox ................................................... 9-120
NOW!................................................... 9.122
DateAdd ................................................ 9.122
DateDiff ................................................ 9.123
Timer .................................................. 9.124
FileDateTime ............................................ 9.124
I Contents I vii

FileLen ................................................. 9.124


MkDir .................................................. 9.124
RmDir .................................................. 9-125
Dir ..................................................... 9-125
Kill ..................................................... 9.127
Beep.................................................... 9-128
Savesetting .............................................. 9-128
Getsetting ............................................... 9-128
Deletesetting ............................................ 9.129
GetAllSettings ........................................... 9.129
Reading and Writing to ASCII Files ............................ 9.130
FreeFile ................................................. 9.131
Reading from ASCII Files ................................. 9.134
Controlling Code Execution ................................... 9.135
For ... Next .............................................. 9-136
While .. .Wend .......................................... 9.137
DO... LOOP ............................................. 9-138
For Each ... Next ........................................ 9.141
If .. .Then .............................................. 9.141
Select Case .............................................. 9.142
Error Handling .......................................... 9.143
Review ...................................................... 9-149

Visual Interface .................................... 10-151


Properties. Methods. and Events ............................. . 10.152
Properties .............................................. 10-152
Control Events ......................................... . 10.154
Common Control Properties ................................. 10.155
Name .................................................. 10-156
Left.Top .............................................. . 10.156
Width. Height ......................................... . l0.157
Visible ................................................. 10.157
Enabled ................................................ 10.157
TabStop ............................................... 10.157
TabIndex .............................................. 10-157
Tag ................................................... . l0-158
ControlTipText ......................................... 10-158
Label ................................................. . l0.158
TextBox ............................................... 10.158
Properties .............................................. 10-159
Events ................................................. 10.160
ComboBox ................................................. 10-160
Properties .............................................. 10-160
Methods ............................................... 10.161
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 .................................................... . l0.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

The Microstation Object Model .Objects .............


The Object Browser ........................................
. l l-187
. ll-188
Auto List Members ......................................... . 11.190
I Contents I ix

Microstation VBA Help File .................................. 11-190


Adding Watches ........................................... . 1 1.192
The Microstation Object Model .............................. . 1 1.192
Application Object ..................................... . 1 1.193
Review .................................................... 11-241

The Microstation Object Model .Enums ............. .I 2.243


MsdDesignFileFormat ....................................... 12.243
The Enumeration List ....................................... 12-245
Review .................................................... 12-277

The Microstation Object Model .Types ...............I 3.279


Review .................................................... 13-283

The Microstation Object Model .Events ..............I 4.285


OnDesignFileOpened and OnDesignFileClosed ................. 14.286
Review .................................................... 14-288

Adding To Documents .............................. .I 5.289


Graphical Elements ......................................... 15-289
Lines .................................................. 15-289
Creating Shapes........................................ . 15.295
Creating Circles......................................... 15-297
Creating Ellipses ....................................... . 15.300
Creating Arcs ........................................... 15-301
Creating Text .......................................... . 15.303
Creating Cells .......................................... 15-304
Creating New Documents .................................... 15-307
Security Issues with Creating Data ............................ . 15.309
Review .................................................... 15-309

Searching In Files .................................. .I 6.311


The Basics of Searching Files ................................. 16-31 1
Using Scancriteria .......................................... 16-316
Multiple Combinations of Criteria ............................. 16-321
Reviewing Three Collection methods ......................... . 16.324
Scan Criteria Methods ...................................... . 16.325
Review .................................................... 16-327

Interactive Modification ............................


Giving Users Feedback and Information .......................
.I 7.329
17.329
Working With Selection Sets ................................. 17-332
X 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

Interface Essentials ................................. 18-391


Interface Basics ............................................. 18.392
Class Module Review ........................................ 18.393
Class Module Lifecycle ....................................... 18.395
ILocateCommandEvents ................................. 18.396
LocateFilter Event ....................................... 18.398
Accept Event ........................................... 18.399
LocateResetEvent ....................................... 18-399
LocateFailed Event ...................................... 18.399
StartEvent ............................................. 18-399
Cleanup Event ......................................... . 1 8.399
DynamicsEvent ........................................ 18-399
Locatecriteria .......................................... 18.404
IPrimitiveCommandEvents ............................... 18.406
Optimizing The Dynamics Event ......................... . 18.426
Review..................................................... 18-430

Using MicroStation's Built-In User Forms ............. 19-431


Declaring Microstation User Form Functions ................... 19.431
The mdlDialogfileOpen Function ........................ 19.432
The mdlDialogfileCr eate Function ....................... 19-439
The mdlDialogfileCreateFromSeed Function .............. 19.441
The mdlDialogopenAlert Function ....................... 19.443
The mdlDialogopenInfoBox Function .................... 19.443
Review..................................................... 19-444

Class Modules ..................................... . 2 0.445


Encapsulating Similar Functionality .......................... . 20.446
Creating Objects with Properties. Methods. and Events.......... . 20.462
Using Class Modules with Collections ........................ . 20.470
Accessing Objects in a Collection ......................... . 20.471
I Contents I xi

Removing Objects from a Collection ...................... . 20.474


Using Custom Class Modules ............................ . 20.474
Review..................................................... 20-478

VBA for CAD Managers ............................. . 2 1.479


Using VBA for Maintaining Standards ........................ . 2 1.479
Cross-Company Standards .................................. . 2 1.485
Tracking Time .............................................. 2 1-490
Drafters ............................................... . 2 1.490
Managers .............................................. 21-490
Accountants ........................................... . 21.490
Auto-Load and Auto-Run ................................... . 21.494
MS-VBA-OPEN-IN-MEMORY ......................... 2 1-495
Protecting Projects ......................................... . 2 1.498
Distributing VBA Projects ................................... . 2 1.501
Working in High Security Mode ............................. . 2 1.502
Review..................................................... 21-503

Microstation File-Based Events ...................... 22-505


OnDesignFileOpened ....................................... . 22.506
OnDesignFileClosed........................................ . 22.507
ISaveAsEvents Interface ..................................... . 22.510
Review..................................................... 22-517

Responding to Microstation Attachment Events .....


. 2 3.519
The IAttachmentEvents Interface ............................ . 23.520
AfterAttach ............................................... . 23.520
After Detach ............................................... . 23.524
AttachmentModified Event .................................. . 23.525
BeforeAttach Event ......................................... . 23.525
BeforeDetach Event ........................................ . 23.526
Review..................................................... 23-526

Model Events ...................................... 24-527


Review..................................................... 24-530

Level Events ......................................


The Active Event ...........................................
. 2 5.531
. 25.535
The Aftercreate Event ...................................... . 25.535
The AfterDelete Event ...................................... . 25.535
The BeforeChangeActive Event .............................. . 25.536
The BeforeDelete Event ..................................... . 25.536
xi i I Contents I
The ChangeAttribute Event ................................. .2 5.536
Review .................................................... 25-536

Change Track Events ............................... .2 6.537


BeginUndoRedo Event ...................................... . 26.537
Element Changed Event .................................... . 26.539
Example 1............................................. . 26.542
Example 2 ............................................. . 26.543
Example 3 ............................................. . 26.547
Example 4 ............................................. . 26.548
Activating the ChangeTrackEvents Interface ................... . 26.549
Review .................................................... 26-550

Non-Graphical Info .Databases ..................... .2 7.551


How Microstation 'link elements to Databases ................. . 27.552
Creating a Database from Scratch ............................ . 27.554
Making Use of UDL Files ................................... . 27.563
Linking Microstation Elements to Database Records ............ . 27.564
Creating Database Records using SQL ........................ . 27.565
Creating a User Interface to view Database Information ......... . 27.566
Review .................................................... 27-569

Tags .............................................. .2 8.571


Getting Information from Tags based on a Selection ............ . 28.572
Getting All Tags in a File .................................... . 28.574
Working with Tagsets ...................................... . 28.575
Getting All Tags of All Files in a Folder ....................... . 28.576
Changing a Tag's Value ..................................... . 28.578
Changing multiple Tags in Multiple Files ...................... . 28.579
Exporting Tag Information to a File .......................... . 28.580
Review .................................................... 28-584

XML .............................................. .29.585


What is XML? ............................................. . 29.585
XML File Structure ......................................... . 29.586
Reading XML Files ......................................... . 29.587
Review .................................................... 29-597

Batch Processing .................................. .3 0.599


Processing Files Listed in an ASCII File ....................... . 30.599
Processing All Files in a Folder ............................... . 30.603
Processing All Files in a Folder and SubFolders ................ . 30.606
I Contents I xiii

Creating a User Interface for File Selection .................... . 30.608


Logging File Batch Processing ............................... . 30.613
Using a Log File ........................................ . 30.613
Tracking Activities with a Database ....................... . 30.615
Storing Information in the Registry ....................... . 30.615
Logging Activities over the Internet ....................... . 30.616
E-mailing Transaction Logs ............................. . 30.619
Review..................................................... 30-621

The Standards Checker ............................ . 3 1.623


Basics of Implementing the Standards Checker .................. 3 1-624
Standards Check A ..................................... . 31.626
Standards Checker Settings .................................. . 31.631
Checking for Standards ..................................... . 31.634
Where we are at this point ............................... . 3 1.634
Standards Checker Reporting ................................ . 3 1.639
Automatically Loading Custom Standards Checker Add-Ins ..... . 31.647
Review..................................................... 31-648

Using the Windows API ............................ . 3 2.649


Declaring API Calls ........................................ . 32.649
Declaring Types ........................................... . 32.650
Utilizing API Calls ......................................... . 32.651
GetLogicalDrives....................................... . 32.652
GetDriveType .......................................... 32-652
GetComputerName .................................... . 32.654
GetVersionEx ......................................... . 32.654
Sleep ................................................. . 32.656
FindExecutable ........................................ . 32.656
GetDiskFreeSpace...................................... . 32.657
GetSystemMetrics ...................................... . 32.658
GetTickCount ......................................... . 32.659
GetUserName ......................................... . 32.660
GetWindowsDirectory .................................. . 32.660
Logonuser ............................................. 32-661
MessageBeep .......................................... . 32.662
Playsound ............................................ . 32.663
ShellExecute........................................... . 32.664
SHGetFileInfo ......................................... . 32.665
Review..................................................... 32-666
xiv I Contents I
Using Third Party ActiveX Controls and DLLs .3 3.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

Working With Excel ................................ .34.689


Connecting to Excel ........................................ . 34.689
Getobject ............................................. . 34.689
Createobject .......................................... . 34.691
New .................................................. . 34.692
Workbooks, Worksheets, Ranges, and Cells ................... . 34.692
Cell and Range Addresses ............................... . 34.697
Working with Worksheets .............................. . 34.702
Tag Extraction ............................................. . 34.707
Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.712

Working With Databases (ActiveX Data Objects)


Primer on ActiveX Data Objects .............................
.3 5.713
. 35.714
......
UDL File Basics ............................................ . 35.716
Connections. Recordsets. and More .......................... . 35.719
Recordsets ............................................ . 35.724
The Find Method ...................................... . 35.727
The GetString Method .................................. . 35.728
AddNew and Update ................................... . 35.729
SQL Essentials ............................................. . 35.730
Select Statement ....................................... . 35.731
Where ................................................ . 35.732
Order By .............................................. . 35.732
Extending ActiveX Data Objects ............................. . 35.740
Examining Database Schema ................................ . 35.745
Excel Files as Databases ..................................... . 35.749
Review ................................................... . 35.754
I Contents I xv

Microstation Leveraging Mathcad via VBA ..........


A Brief Introduction to Mathcad .............................
. 3 6.755
. 36.756
Adding a Reference and using the Object Browser .............. . 36.756
Basic Macros that Communicate With Mathcad ................. 36.763
Region Objects .The Basis for All Calculations ................. . 36.766
The Mathcad Object Model.................................. . 36.769
Application ........................................... . 36.769
IMathcadApplication2 .................................. . 36.770
Driving Microstation Geometry from Mathcad ................ . 36.771
Review..................................................... 36-782

Accessing Data from External Applications ..........


ActiveX I COM Basics ......................................
. 3 7.783
. 37.784
References. Early Binding. and Late Binding ................... . 37.785
Getobject. Setobject. and New .............................. . 37.788
When to use Getobject. Createobject. and New ............ . 37.790
What does 'WithEvents' do for us?............................ . 37.792
Run Macros from Excel or Microstation? ...................... . 37.793
Controlling Microstation from within Excel ................... . 37.794
Running Excel Macros .................................. . 37.797
Review..................................................... 37-805

Writing VB6 Applications ........................... 38-807


Differences between VBA and VB6 ........................... . 38.807
VB6 Project Structure....................................... . 38.809
Controlling Microstation with VB6 ........................... . 38.816
Creating an ActiveX Control in VB6 ...................... . 38.822
Debugging ActiveX Control Projects ...................... . 38.827
Compiling our ActiveX Control .......................... . 38.830
Creating ActiveX DLLs ................................. . 38.832
Compiling and Distributing Applications ..................... . 38.837
Compiling Applications ................................. . 38.838
Distributing VB6 Applications ........................... . 38.839
Review..................................................... 38-847

Using VB.NET ..................................... . 39.849


VB.NET Introduction ...................................... . 39.850
You can do this in VB.NET! ................................. . 39.856
A DGN Browser Application ................................ . 39.862
VBA to VB.NET Reference .................................. . 39.866
Everything is an Object ................................. . 39.866
Overloaded ............................................ . 39.867
Procedures and Functions ............................... . 39.868
xvi I Contents I
Accessing ASCII Files................................... . 39.868
Traversing a Folder and its Subfolders .................... . 39.870
Getting All Files in a path ............................... . 39.871
Returning Function Values .............................. . 39.872
Windows API Calls..................................... . 39.872
Distributing VB.NET Applications ........................... . 39.877
Review .................................................... 39-880

Additional Sources ..................................... 881

Index ................................................. 883


Introducing VBA

"LET'SSTART AT THE VERY BEGINNING. IT'S A VERY


GOOD PLACE TO START."
El WhatisVBA?
El Why should we learn it?
El When should we use it?
El How do we use it?
El What does it look like?
These are five very good questions and they deserve answers.

WHATIS VBA?
VBA is an abbreviation for Visual Basic for Applications. Microsoft
licenses VBA to companies such as Bentley Systems, Inc., so users can
customize the company's software. Then, companies that develop
world-class software, such as Microstation, can give their customers the
best set of tools available. These companies know that one way to
accomplish this goal is to empower customers to modify and
personalize their software to meet individual needs.

1
2 I Chapter 1 : Introducing VBA I

WHY LEARNVBA?
Learn VBA to rapidly develop programs that meet your individual
needs. Much of what you learn in MicroStations VBA environment can
be used in other VBA environments. The first two-thirds of the VBA
abbreviation is VB. Visual Basic includes both the Visual Basic
programming language and its programming environment. A finishes
up the final third of VBA. The X is the Application-specific Objects
and Application Programming Interfaces (APIs).
If we think of VBA as being two-thirds Visual Basic and one third
Application, we could state that two-thirds of everything you learn in
this book is directly applicable to other VBA environments. For
example, if you learn Microstation VBA, you would be 2/3 of the way to
knowing Microsoft Excel VBA. And this is not far off. So, in addition to
being able to customize Microstation to meet your needs, learning VBA
allows you to leverage other VBA-enabled applications.

WHENSHOULDYou USE VBA?


Only under the direct supervision of an adult?
Between the hours of 8 AM and 5 PM?
Holidays? Weekends?
The real question you should be asking yourself is, Can the program I
need to write be written in VBA? If the answer to this question is YES,
then it should probably be written in VBA. And as you learn more about
VBA, more and more often the answer to this question will be YES!

How Do WE USEVBA?
Microstation VBA programming is stored in files with an .mvba
extension. To run any of the code in one of these Microstation VBA files
you must first load the file. Before we go any further, lets create a new
I How Do We Use VBA? I 3

drawing file named Introductiondgn. Go to the Microstation menu


Utility > Macros > Project Manager to open the Project Manager.

We use the Project Manager to begin new VBA projects and open
existing VBA projects.

In this dialog box, click the Load Project button. Now, browse to the CD
included with this book for a folder named MVBA Files. In this folder
4 I Chapter 1 : Introducing VBA I
you will find a file named Introductionmvba. Select this file and click
the OK button.

This loads the .mvba file into Microstation and displays it in the VBA
Project Manager.

Opening an MVBA file does not close the Project Manager. The Project
Manager remains open until you click the Close button in the upper
right-hand corner of the dialog box.
Now that we have loaded an .mvba file, we can run some code. How do
we do it? There are a few ways. Lets 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
1ntroduction.rnvba file. In the VBAPM, select the VBA Project
1ntroduction.rnvba. Now look at the top of the VBAPM for a triangle
that looks like the play button on a VCR. This is the Run Macro button.
I How Do We Use VBA? I 5

When you click it, the Macros dialog box opens, which allows you to
select which macro (procedure or function) you want to run.

Select P r o c e d u r e A 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. P r o c e d u r e A draws a line from (0, 0,O) to (10, 10,O) in the active
file. If the macro is run and the line is not visible, use the Fit View button
to zoom the active view to display all of the contents of the file.
Remember, the steps to running an MVBA macro are:
1 Load the MVBA file using the VBAPM (VBA Project Manager).
2 Select the project in the list of projects.
3 Click the Run Macro button in the VBAPM, or click the
Microstation menu Utilities > Macro > Macros, or hold down the
<ALT> key on your keyboard and press <FS> key.
Its a three-step process. Of course, if the .mvba file is already loaded,
You do not need to load it each time you run the macro. You can run a
specific macro by using one of three methods described above in Step 3.
You have just run a macro using the VBAPM. Now run one by using the
<ALT+FS> keyboard shortcut. Hold down the <ALT> key and then
press the <FS> key to display the Macros dialog box. Select P r o c e d u r e C
from the list and click the Run button. P r o c e d u r e C draws a square using
6 I Chapter 1 : Introducing VBA I
lines from (0, 0,O) to (10,0,0) to (10,10,0) to (0,10,0) and finally back
to (0, 0,O).
That's all there is to running a Microstation VBA macro. Load it and
run it.

WHAT DOES VBA LOOK LIKE?


Here is the VBA code behind that macro:

Sub P r o c e d u r e A o
I ********
'* T h i s P r o c e d u r e d r a w s a l i n e f r o m (10, 1 0 , 0) t o ( 3 0 , 1 0 , 0)
I ********
D i m S t a r t p o i n t As P o i n t 3 d
D i m E n d p o i n t As P o i n t 3 d
D i m M y L i n e As L i n e E l e m e n t
StartP0int.X = 0
S t a r t P 0 i n t . Y = 0: S t a r t P 0 i n t . Z = 0
EndP0int.X = 10: EndP0int.Y = 10: E n d P 0 i n t . Z = 0
S e t M y L i n e = CreateLineElementZ(Nothing, ~

S t a r t p o i n t , Endpoint)
A c t i v e M o d e l Reference.AddE1 ement MyLine
End Sub

VBA Projects are broken up into blocks of code called procedures,


functions, and events. Each block of code has a name. The procedure
shown above is named ProcedureA. Comments in the code begin with an
apostrophe. Everything after the apostrophe is part of the comment.
Variables are declared with 'Dim' statements and are then assigned
values or set to objects. Code in procedures, functions, and events runs
from top to bottom. Together we will write a large number of functions
and procedures as we study Microstation VBA.
Back to the code in ProcedureA. It does not have a graphical user
interface - it is just code. Writing code is one part of VBA
development.
I Review I 7

The other part of VBA development is the graphical user interface


(GUI), such as buttons, text boxes, and labels.

Some of the applications we write will have no GUI, but we will also
explore the visual side of Visual Basic.

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+FS> 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.
The VBA Project
Manager

You have already seen how to display the VBA Project Manager.
Remember, go to the Microstation menu Utilities > Macro > Project
Manager. We used the Project Manager to load a VBA project and run a
couple of macros contained in that project. Lets take a more
comprehensive look at what the Project Manager can do for us.
The Project Manager gives us the ability to load existing VBA
projects.
The Project Manager allows us to run the procedures and
functions of projects that have already been loaded.
Start new VBA projects using the Project Manager.
Unload VBA Projects that are already loaded.
Save loaded VBA Projects to a new location and/or a different
file name.
Enter the Visual Basic Editor from the Project Manager.
Record macros from the Project Manager.
Auto-Load VBA Projects so projects are loaded each time
Microstation is started.

9
10 I Chapter 2: The VBA Project Manager I
We can use the Microstation menu to display the VBA Project Manager
or we can hold down the <ALT> key and press the <F8> key to display
the macros that are loaded and are ready to be run.
We need to be careful when discussing the VBA Project Manager. The
term Project Manager is so generic it could be confused with other
products or functionality. For brevity we will refer to the VBA Project
Manager as the VBAPM from time to time throughout this book.
Now that we have identified the VBAPMs functionality in general it is
time to examine it in greater detail.

VBA PROJECT FUNCTIONALITY


MANAGER
The following graphic shows the VBAPM with its elements identified
with leader lines. We will refer to the image during the remainder of this
chapter.

You are prompted for the location of the new .MVBA file
and for its name.

This button is enabled only when a n existing project is


I VBA Project Manager Functionality I 11

Click this button to display the Run Macro dialog box

activated, activities in Microstation are recorded to a

Macro Recorder automatically names the macros. You


can rename recorded macros in the VBA Editor.

column, a checkmark indicates the file is set to Auto-

We have just identified ten things that you can do directly from within
the VBA Project Manager. One of these is Run Macro which, rather
than actually running a macro, displays the Macros dialog box.
12 I Chapter 2: The VBA Project Manager I

MACROS Box
DIALOG
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.

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

Draw-A-Li n e ~ F r o r n ~ O ~ O ~ O ~ t o We
~ l 0 ~can
0 ~ 0name
. it P r o c e d u r e A and
enter a description in the Macros dialog box.
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. Its simple. Heres 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-1 into the TextBox and click the
Create button, a new Procedure named ProcedureA-1 is created. Of
course, no code is entered into the procedure after it is created. That is
our job. We can now select ProcedureA-1 from the ListBox, click the Edit
button, and go into the new procedure in the VBA Editor to begin
writing code.

The VBA Project Manager is useful for performing a number of tasks.


Among them are:
To load and unload VBA projects (MVBA files).
To save existing VBA projects to new files and locations.
To begin new VBA projects.
To record macros into existing VBA projects.
To use Auto-Load to automatically load VBA projects within
the VBAPM.
To enter the VBA Editor from within the VBAPM.
The VBA IDE

Open the VBA IDE PDQ!!! Yes, the IDE is WYSIWYG. GM?
Translation: Open the Visual Basic for Applications Integrated
Development Environment Pretty Darn Quick!!! Yes, the Integrated
Development Environment is What You See Is What You Get: Got
Milk?
The VBA IDE is where we do our VBA programming work. As with
most Windows programs, the VBA IDE is composed of three elements:
Menus
Toolbars
El Windows

15
16 I Chapter 3: The VBA IDE I

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. Lets look at the menu items that are available in VBA.

File Menu
Import File imports existing
Ctrl+M form (.frm), module (.bas), and
class (.cls) files into our project.
Export File exports forms,
modules, and classes from our
project to their own .frm, .bas,
and .cls files. After these files have been exported, they can be
imported into another project.
Remove removes forms, modules, and classes from our project.
When we attempt to remove an element from our project we are
asked if we want to export it (save it) first.
I Menus I 17

Print allows us to print code and/or forms.


Close and Return to Microstation hides the VBA environment
and gives Microstation focus.

Edit Menu
Undo and Redo are standard
Windows menu items.
Cut, Copy, and Paste perform
standard Windows Clipboard
operations.
Clear deletes selected text or
objects.
Select All selects all text when in a
Code window or all controls when
in a User Form.
The Find, Find Next, and Replace
menu items perform standard Find
and Replace functions.
Indent indents the selected code by *
one tab to the right. Outdent (is
Outdent a real word?) shifts the selected code by one tab to the
left.
List Properties/Methods displays the Properties/Methods list.
List Constants works with an API call that utilizes constants. A
list of the applicable constants is shown.
To use Quick Info, set the cursor on a variable, an object, or an
objects property or method and then click Quick Info to display
the type of object or variable on which the cursor was placed.
Parameter Info displays information about the Method the
cursor is over.
Complete Word shows the list of Constants and Methods in
VBA so we can select something from the list.
Bookmarks sets and removes bookmarks in our code and
moves from bookmark to bookmark. A bookmark is a flag that
18 I Chapter 3: The VBA IDE I
lets you quicklyjump to a line of code. Bookmarks are not saved
with .mvba projects.

View Menu
El When looking at a user form,
click Code to jump to the code
behind the form.
El Object displays the form
associated with the code we are
looking at.
El Click on Definition when the
cursor is over the item you want to
look at to quickly display where the
variable is declared or the method
is defined.
ElLast Position moves the cursor
to the previous line of code the
cursor was in.
El Object Browser, Immediate Window, Locals Window, Watch
Window, Call Stack, Project Explorer, PropertiesWindow, and
Toolbox display a window with the same name.

Tab Order displays the Tab Order properties of controls so we


can see the order in which controls receive focus when the user
hits the Tab button in the form.
Toolbars toggles the display of the Debug, Edit, Standard, and
User Form toolbars.
El Click on Microstation to bring the Microstation window to the
forefront.
I Menus I 19

Insert Menu
Procedure displays the Add Procedure
dialog box to begin new procedures. This
dialog box is most useful for creating new
Properties for Class Modules.
UserForm, Module, and Class Module
inserts these new objects into our project.
One way to speed up our development is to reuse code that has
already been written. If we place code in ASCII Text Files, insert
snippets into our project by clicking File and then selecting the
file to insert.

Format Menu

Use the Format menu to perform standard


formatting when editing a User Form.

Debug Menu
The Debug menu allows us to
perform debugging operations
on our code. We will cover this
functionality in Chapter 9
"Standard VBA Calls".
20 I Chapter 3: The VBA IDE I

Run Menu
Run Macro, Break into, and Reset
code execution by using these menu
items in the Run menu.
Design Mode is a standard VBA
*
button that does nothing substantive in
the Microstation implementation of VBA.

Tools Menu
References allows us to add a
1
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.
By default, 14 controls display in the toolbox for use in our
forms. We can add more controls by selecting the Additional
Controls menu item.

Macros displays the Macros dialog box where we can create,


edit, run, delete, and debug macros in our project.
Change preferences such as font size, tab width, and grid
settings by clicking on Options.
The Properties menu item displays the properties for the active
VBA project. In the image shown above, the project is named
Default.
Digital Signature allows us to sign our VBA projects. This
assures end users that the code they are going to run is created
by a specific company.

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 manager with an add-in that has been loaded. Add-
ins can be loaded based on the Load Behavior settings.

Window Menu

These are the standard menu items


available in nearly every Microsoft
Windows program.

Help Menu
We will cover Help issues in the
next chapter. One way to get there
is by clicking the Microsoft Visual
Basic Help menu item.

About Microsoft Visual Basic displays the About dialog box.


22 I Chapter 3: The VBA IDE I

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 MivoStatmn
Notice how holding your cursor over an icon displays the icons tool tip.
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.

Debug toolbar

The Debug toolbar displays the functionality found in the Debug menu.
I Windows I 23

UserForm tool bar


The UserForm toolbar exposes
functionality found in the Format
menu.

WINDOWS
Use the toolbars and menu items to display and hide VBA windows.
Lets 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.
In this project we have a form named
UserForm1, a module named Module1 and
a class module named Class1 . The view
shown uses folders to group the common
types of objects.

Click on the Folder icon in the


top of the Project Explorer to
turn off Folders and display the
objects in alphabetical order.
24 I Chapter 3: The VBA IDE I

Object Browser

The Object Browser gives us a way to explore the objects (classes)


loaded into the current VBA project. In addition to the objects
themselves, we see a list of properties, methods, and events associated
with each object under the Members list. The gray area at the bottom
of the window gives us the declaration of the selected method, property,
or event. We can display All Libraries or select a specific library. We also
have the ability to search the loaded libraries.
We will cover the Object Browser in more detail in the next chapter.
I Windows I 25

Properties Window

Objects in VBA have names. For


example, this user form has the name
UserForml. We can use the
Properties window to change this
forms name, color, and other
properties. The Properties window is
used extensively when working with
forms and controls on forms.

Watch Window

The Watch window is a favorite among VBA developers. It allows us to


watch the value of a variable, object, or property. As we can see above, I
added a watch to a variable named MyApp. This variable points to the
Microstation Application. Take a look at all of the properties with which
we can work.
26 I Chapter 3: The VBA IDE I

Locals Window

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 variables 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
D i m MyApp As A p p l i c a t i o n
S e t MyApp = Application
D e b u g . P r i n t MyApp.Caption

the caption of the Microstation application is printed to the Immediate


window. For this reason, it is also called the Debug window.
The other thing the Immediate window does is it allows us to execute
code immediately. For example, we can type
MsgBox L e a r n i n g M i c r o s t a t i o n V B A
I Windows I 27

in the Immediate window and press the <Enter>key. When we do so, a


MessageBox displays.

Call Stack Window

As we step through our code line-by-line or break into our code as it is


executing, the Call Stack window shows us where we are (the top line),
where we started (the bottom line), and how we got there (all of the lines
in between). There are times when one procedure calls another
procedure which calls a function which calls a procedure. Knowing how
we arrived inside a procedure or function can help us debug it.

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.

All of the windows discussed so far are dockable except for the Toolbox.
This means they can be snapped to the bottom, top, right, or left
window of the VBA IDE. These windows dockable property is set in the
28 I Chapter 3: The VBA IDE I
Docking tab of the Options dialog box. To view this, go to the Tools
menu in VBA and select Options.

OK

If an attempt to dock a window fails, look at the Docking property of the


window in the Options dialog box and turn on Docking for the specific
window you want to dock. As with many applications, these windows
are docked by dragging the window to the edge where you want the
window docked. They are un-docked by dragging the window away
from the edge where the window is currently docked.

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.
I Windows I 29

A single CommandButton has been added to this form. This form


window allows us to place controls on it. Remember, the controls are
placed from the toolbox to the form.
What happens when we are running this form and the user clicks the
button? Code is executed. Double-clicking the button takes us to Code
window behind the form. Another way to see the code is to right-click
on the button and select View Code.

This is the C l i c k E v e n t of
CommandButtonl. View
Code takes us to the default
event of the control we Private Sub CommandButtonl-Click()
Dim MyApp As Application
right-click over. So, here we Set MyApp = Application
Debug.Print MyApp.Caption
can see the C1 i c k Event. Are DrawL ine
there other events we can End Sub

work with? How do we see Sub DrawLine ( )

them and write code in


them?
Take a look at the top of the
Code window. There are two
ComboBoxes. The left one
Private Sub Comman
Dim MyApp As A contains the controls and
Set MyApp = Ap
Debug.Print My objects available in this Code
DrawL ine
End Sub
window. The right one
contains the events we can
Sub DrawLine ( )
MsgBox "XI is work with. Selecting an event
End Sub
30 I Chapter 3: The VBA IDE I
from the right ComboBox takes us into the code for that event.
Open Module (Code Module) and Class Module windows by double-
clicking on their icons in the Project Explorer or by right-clicking on the
icons and selecting View Code. They look exactly like the Code window
shown above.
We have spent a few pages discussing the VBA IDE. As we continue
learning Microstation VBA, we will discover other facets of the IDE and
get into more detail.

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. Thats easy. When
learning VBA, however, you dont 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
dont know the correct terminology, you wont 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:
Terminology
Help Files
TheNet
The Object Browser

31
32 I Chapter 4:Finding Help I

TERMINOLOGY
Thingy. Dilly Whopper. Whatchamacallit. Gizmo. Whether we are
asking a person or a computer, these words will get us nowhere. How
can we get a little closer to the right keyword?
Lets begin by looking in VBA.
Holding your cursor
over a variety of objects
displays a Tool Tip.
There is a ComboBox
m icon in the Toolbox. If
we ask about a
ComboBox we are
more likely to find answers than if we ask about a DropDown. Both
combinations of words may make sense to us, but using the correct
name for the control gets us closer to finding answers to our questions
than using terminology that, although descriptive, is not correct.
Since the terminology used in VBA may be foreign to you when getting
started, it is a good idea to make notes or highlight areas of this book
and other resources when you come across a word or phrase you want to
remember or that you may want to be able to find quickly at a later date.
For example, if you are asked to provide a string, you may produce a
piece of flexible material useful for restricting blood circulation in ones
index finger with the intent of reminding you of something. As for me,
Im 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 fingerless. Or is it finger-free?Digitless?
I Terminology I 33

What is a string when it comes to VBA? It is a type of variable that can


hold text, numbers, and other characters. This is a test is an example of
a string. Since the word string is very different when dealing with VBA
when compared to Benjamin Franklins experiments with electricity,
highlighting the definition of a string type variable in a book may be
helpful.
In addition to highlighting existing text, get out a pen or pencil and
write in the margins of this book.
Chicken Soup for the VBA Programmer. The VBA Word of the Day.
The VBA Programmers Daily Calendar. These products may not exist
but they could be very helpful. Why? Frequent and regular exposure
reinforces retention.
If your goal were to obtain a dark tan, you would want regular exposure
to the sun. If your goal were to bake bread, it would be out of reach if
you rarely stepped inside a kitchen. Practice makes Perfect, No Pain,
No Gain, and If at first you dont succeed, try, try again. We have
heard these statements over and over again. Each of them reminds us
that frequent and prolonged exposure and practice is usually necessary
for success in any endeavor. While you dont need to write a thousand
lines of code every day to learn VBA terminology, 20 lines of code every
day will do more than 100 lines of code only on Monday mornings.
If you expose yourself to VBA frequently, the terminology becomes
familiar and you will be in a better position to find the help you need.
34 I Chapter 4: Finding Help I

HELPFILES
One way to display the VBA Help File is to go to the Help menu in VBA
and select Microsoft Visual Basic Help.

Visual Basic
See i\k Spea!!c>

Welcome to the Visual Basic documentation.


Visual Basic includes many documentation tools,
each designed to help you learn and use a
particular aspect of the product. The documentation
provided with Visual Basic includes the following:
Visual Basic User Interface Help
Look here f o r Help on interface elements of the
Visual Basic Editor, such as commands, dialog
boxes, windows, and toolbars.
Visual Basic Conceptual Topics
The Conceptual Help topics include information
to help you understand Visual Basic
programming.
Visual Basic HOW-TO
Topics
Look in the How To section of Help to find useful
common procedures, f o r example, how to use
the O b j e c t B r o w s e r or how to set Visual Basic
Environment options.
Visual Basic Language Reference
The Language Reference is the place to find
Help on Visual Basic the language: all its
methods, properties, statements, functions,
operators, and objects.

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? Lets begin in the Contents
tab and drill down to the ComboBox starting with the Microsoft Forms
Reference.
I Help Files I 35

Contents tab

ComboBox Control
See Also Example Properties Methods
Events 4pftiimsr
Combines t h e features of a ListBon and a TextBox.
The u s e r can e n t e r a new value, as with a TentBon, o r
t h e user can select a n existing value as with a ListBon.
Remarks
If a ComboBox is bound t o a data source, then t h e
ComboBon inserts t h e value the user enters o r selects
into t h a t data source, If a multicolumn combo b o x is
bound, then the BoundColumn property determines
which value is stored in t h e bound data source,
The list in a ComboBon consists of rows of data. Each
r o w can h a v e one o r m o r e columns, which can appear
with o r without headings. Some applications do not
support column headings, others provide only limited
support

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.
I Chapter 4: Finding Help I

Index tab

CompareMode property clearing


Filter function color
InStrRev function comparing
Replacefunction converting
Split function cutting and pasting
wildcards entering
string conversion from numbers
String data type importing
String function Iooping
String keyword searchinglieplacing
String$ function String data type
strings text files
aligning inserting
character TextStream oblect
comparing The binary compatibilityDLL or E)
concatenating The binary compatibilityDLL or E)
converting Then keyword
data types This [Me keyword]
fixed-length Tile Horizontallycommand
formats Tile Vertically command
justifying Time function
leftmost characters time intervals
length adding
manipulating difference
matching Time keyword
middle characters time stamp
removingspaces Time statement
repeating Time$ function
replacing Timer function
returningfrom functions timers
reversing times
rightmost characters adding
searching converting
spaces creating
substrings Date data type
variable-length determining

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 dont have the exact terminology, getting close to the correct word
may link you to the correct topic.
I Help Files I 37

Search tab
Use the Search tab to enter a word
or series of words to search for in
the help topics. It returns a list of
all help topics containing the
word(s) entered. For example, if Toolbox Visual Basic ... 2
Unable to unload withi... Visual Basic ... 3
you enter combobox, you are UnderstandingObject... Visual Basic ... 4
MatchFound, MatchR... Microsoft Fo... 5
returned a listing of 67 topics. Layout Event, OldLeft... Microsoft Fo... 6
Style Property Microsoft Fo... 7
Some topics are properties such as DblClick Event, CanP... Microsoft Fo... 8
ComboBox Control, A,.. Microsoft Fo... 9
List Property. Other topics are Ways to put data in a ... Microsoft Fo... 10
List Property Microsoft Fo... 11
instructional, such as Ways to Thingsyou can do wit ... Microsoft Fo... 12
Style Property Example Microsoft Fo... 13
put data in a ListBox or MatchEntryProperty, ... Microsoft Fo... 14
AutoTab Property Microsoft Fo... 15
ComboBox. Keep in mind that BoundColumnProperty Microsoft Fo... 16
Text Property Microsoft Fo... 17
most help topics are linked to CurX Property Microsoft Fo... 18
TextColumn Property Microsoft Fo... 19
related topics. So, we could begin Value Property Microsoft Fo... 20
Locked, DropButtonS... Microsoft Fo... 21
with a search for combobox and DropDown Method Ex... Microsoft Fo... 22
DragBehavior Property Microsoft Fo... 23
read far more than 67 topics by Listwidth Property Ex... Microsoft Fo... 24
ListRowsProperty Ex... Microsoft Fo... 25
jumping to other help topics. Linecount Property Microsoft Fo... 26
Add items to a list usin... Microsoft Fo... 27
Listlndex Property Microsoft Fo... 28
Liststyle Property Microsoft Fo... 29

Favorites tab

t data in a Listsox or

See Also C-:oe:,i.c~


I n a ListBox o r with a single column,
the AddItem rn er an effective
technique for adding an indiv o the list.
I n a rnulticolurnn ListBo. o r ,however,
the List and Column properties offer another
technique; you can load the list from a two-
dimensional =.

If you find a particularly helpful help topic or one that was difficult to
find, add it to your Favorites. The Current topic text box displays the
38 I Chapter 4:Finding Help I
default topic title. Fortunately, you can change this description to
whatever you want it to say. For example, you could change it to
ComboBox - Adding To the List. Then click the Add button.
Favorites is one of the best ways to personalize the standard Visual Basic
Help file. Sure, you can print out page after page after page, use a
highlighter and make a binder. That is a fine way to catalog what you
have learned and create additional reference material. But Favorites is a
quick way to find bookmarkedtopics and jumps to linked topics. It also
keeps the Copy and Paste functionality available.
To sum up, VBA stands for Visual Basic for Applications. Thus far in
this chapter, we have been discussing how to find help for the VB
portion of VBA. What about the Y?The Application? Good question.
Learning everything about the VBA programming language will give us
some good background but will not get us very far when attempting to
interact with Microstation.
I Help Files I 39

MicrostationVBA Help File

Microstation V8
Visual Basic for
Applications
p Loading and runninga VBA macro Visual Basic and
VBA are thoroughly
Frequentlyasked MicroStationVBA Questions modern object-
oriented
Recording and RevisingMacros programming
environments used
Automatingcommon MicroStationtasks by both professional
Working with MicroStationObjects application
Working with MicroStationEvents developers and
Customizing MicroStationwithvisual Basic casual
programmers.
Convertingfrom MicroStationBasic toVBA Visual Basic is the
primary
Changes for MicroStationVBXMEdition development
platform f o r a large
number of
commercial
products, some of
which you may use
on a daily basis.
Visual Basic f o r
Applications shares
most of Visual

Microstation has its own VBA Help file. It contains MicroStation-


specific help for VBA. Searching for the file microstationvba.chm on
your computer should show us where it is and let you open it.

Vertex List Example


This example illustrates some of the methods of the
VelteXL1St interface. The example 15 a simple primitive
command t h a t implements event handlers for start, data
m Adding the Contents of a Fence to a Named Group point, and reset. Because the other event handlers of
IP,imitiveCommandEvents do nothing in this example,
AnalyzeArc they have been omitted.
H ApplicationElement Evample Mort o f the logic f o r this example I S in the data point
p A m By Length event handler. It tests t o determine if it has a r a v e d
H Area Booleans reference t o an element. If not, it tries t o locate an
Attaching and Searching a Cell Libraiy element using LocateElement. If it successfully finds an
B spline Curve Point Extraction element that rupportr t h e VertexLirt interface, it
retriever the list of verticer using GetVerticer. It prints
B spline Surface From Gridded Point Interpolation the vertex list, and i a v e s the reference t o the object. On
p B spline Surface From Poles rubsequent data points, it detects that it already h a r an
p B spline Surface From Scattered Point Appioximation element. It user GetClorertSesment t o get the index of
H Centering theview at the Curroi the first vertex o f the segment closest t o the data point.
p Changing a Relerence File Path from Absolute to Logical
k i n g t h a t information, it prints the range of t h e closest
segment.
Changing an Attachment to Releience the Oelault Model
p Changing Coordinate Readout in a S a v d s Event The reset event handler in this example j u s t restarts the
command. It invoker CommandState.StartPrImltlve.
p Changing the Update Order ol Attachments StartPrimitiue first resets MicroStationr command

One of the most helpful sections in the Microstation VBA help file is the
Examples folder, which contains excellent explanations as well as the
code to perform specific tasks.
40 I Chapter 4:Finding Help I
Another excellent way to open the Microstation VBA Help file is to
select a Microstation-specific API call in the Object Browser or in our
code and hit the <F1> key on the keyboard.

THENET
Got Net? http://msdn.microsoft.com/isv/technology/vba/default.aspx
gets us to Microsofts 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
Microstations VBA-specific implementation here, you will find many
other examples on how to accomplish specific tasks in the VBA
environment.
I The Net I 41

Google, Yahoo, and other search engines can unlock the rest of the
Internets 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?

~ ~ L ~ C 7I 8279 s ~ - rUP^^~ i W8A ~ ~ tine^


~
The follo:+irig GEOPAK \iBk r w t i n e s are provided tree far voiir use. We at Bentley I?OUI:that you red?
prududivir), bsriclits from atitomaliny GEOFCK Civi! Engineering Su!te with VBA.

~ ~ L ~ C ~ ~Laz;?s
________________ ~ _________
r u- C
i ~~ en s~ i ~W ~~ rr i~ ~tinbiMl ~~i ~~~ ~ . u V~8 t ~ ~ ~ ~ R
Th!s technical Dociiment provides s description #f the variables in MicroStation V8 !Ziiii? Editiun, V8 0
and di3.t)
..............................................................
.............................................................

Among the Bentley


Discussion Groups we find
Bent/ey.microstution.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 I Chapter 4:Finding Help I
able to help others by answering their questions in this Discussion
Group.

You can access any of these groups via must papular discussion gruup neimre
from a Web browser-, visit htip:i/discus5ion,ien:lry , c o n .

g a n t t o past a test article from a newsreader? Ga to Bm:leg.tcstpcsts.

M ~ c ~ ~ S t a ~ ~ ~ n
.
R e ntle f n?i c m stati o n v 8 >. ne a rl Y a cce s s I ne A 2
~

BROWSER
THEOBJECT
We talk to Microstation through its Object Model. The top level of the
Microstations Object Model is the Application Object. Using the Object
Browser in VBA is a great help when you are trying to discover
something about an Object Model. As shown, you can restrict browsing
to the Microstation DGN library so all Microstation Classes show up in
the ListBox on the left. Selecting Application in the left ListBox
I The Object Browser I 43

displays its properties, methods, and events in the listbox on the right
side of the window.

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
Files properties, methods, and events in the Members list on the right.
44 I Chapter 4:Finding Help I
Selecting AddNewLevel in the Members list shows that we need to
supply a LevelName when using AddNewLevel. It also shows that
AddNewLevel returns a Level Object.
One reason the Object Browser is helpful is because you can start at a
very general level (Application) and work down through the object
model to the object, property, method, or event for which you are
looking. We can literally browse through the available objects and APIs
using the Object Browser.
Other ways to find/get help? Take a Bentley-approved VBA training
class or attend the annual Bentley Developer Conference.

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, Forms, and
Class Modules

We have already discussed the basics of how Microstation VBA projects.


modules, forms, and classes are used to create programs that improve
productivity and accuracy. That much we know. Its time to learn when
to use each of these design elements and how they work together.

In this Chapter:
Modules
Forms
Classes
Procedures and Functions

MODULES
Code modules are the foundation of every VBA project. We use them to
declare variables that can be used from within the code module, by
other code modules, by forms, and even by class modules. Windows API
functions are declared in modules so the API calls can be used in our
project (more on Windows API functions later in the book). Procedures
and functions inside modules can be run from the VBA Project

45
46 I Chapter 5: Modules, Forms, and Class Modules I
Manager. In fact, code modules are so essential that an initial code
module is created every time a new VBA project is created. Procedures
written in code modules are the starting point for running code and
displaying forms.
Enough talking. Lets write some code.
Lets begin by creating a new VBA project named Chapter 05. Save it in
the folder C:\MicroStution VBA. After this new project is created, you can
see that a code module named Module 1 is created automatically.
Rename this module modCh05.
Continue by creating a new procedure named Main. Inside the code
module, type

Sub M a i n 0

When you press the


<Enter> key after typing
the above code, VBA
(GenerPI) Main
finishes the new procedure
Sub Main()
by entering an Exit Sub
End Sub
for us. At this point, the
module should look like
this:
The next thing we are going to do is enter some code in our new
procedure Main.

Sub M a i n 0
Declare Variables
D i m M y L i n e As L i n e E l e m e n t
D i m MyCir As E l l i p s e E l e m e n t
D i m C e n P t As P o i n t 3 d
D i m L i n e S t As P o i n t 3 d
D i m L i n e E n As P o i n t 3 d
D i m R o t M a t r i x As M a t r i x 3 d
Create Horizontal Line
LineSt.X = -1
LineEn.X = 1
S e t MyLine = Application.CreateLineElernent2(Nothing. LineSt, LineEn)
A p p l ic a t i on . A c t i v e M o d e l R e f e r e n c e . A d d E 1 e m e n t M y L i n e
Create Vertical Line
LineSt.X = 0: L i n e S t . Y = 1
I Modules I 47

LineEn.X = 0: LineEn.Y = -1
Set MyLine = Application.CreateLineElernentZ(Nothing, L i n e S t . L i n e E n )
Appl ication.ActiveMode1 Reference.AddElement MyLine
'Create Circles
Set MyCir = Application.CreateEllipseElement2(Nothing, ~

CenPt, 0.25, 0.25, RotMatrix)


Appl ication.ActiveMode1 Reference.AddElement MyCi r
Set MyCir = Application.CreateEllipseElement2(Nothing, -

CenPt, 0.5, 0.5, RotMatrix)


Appl ication.ActiveMode1 Reference.AddElement MyCi r
End Sub
The code above may look like a whole lot of gibberish at this point, but it
will make much more sense as we continue to learn VBA together.
Notice the comments inserted into the code. Remember, comments
begin with an apostrophe (I).

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 -7

wish.
If we need to draw the target centered at (4,5,0) we can copy and paste
the code, and rename the procedure to Mai n2. And then we can create
The more M a i n 3 with different coordinates, then Main4, then M a i n 5 and so on.
hard-coding
we do, the less Right? Well, we could do that but there is a better way.
offen we will Let's change the way we are doing things a little bit. Instead of having
be able to run
our macros. Mai n 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 Double)


'Declare Variables
Dim MyLine As LineElement
Dim MyCi r As El 1 ipseElement
48 I Chapter 5: Modules, Forms, and Class Modules I
D i m C e n P t As P o i n t 3 d
D i m L i n e S t As P o i n t 3 d
D i m L i n e E n As P o i n t 3 d
D i m R o t M a t r i x As M a t r i x 3 d
Create Horizontal Line
LineSt.X = CenX - 1
L inest .Y = CenY
LineSt.Z = CenZ
LineEn.X = CenX + 1
LineEn.Y = CenY
LineEn.Z = CenZ
Set MyLine = Application.CreateLineElernentZ(Nothing, L i n e S t . LineEn)
A p p l ic a t i on . A c t i v e M o d e l R e f e r e n c e . A d d E 1 e m e n t M y L i n e
Create Vertical Line
LineSt.X = CenX
LineSt.Y = CenY + 1
LineSt.Z = CenZ
LineEn.X = CenX
LineEn.Y = CenY - 1
LineEn.Z = CenZ
Set MyLine = Application.CreateLineElementZ(Nothing, L i n e S t , LineEn)
A p p l ic a t i on . A c t i v e M o d e l R e f e r e n c e . A d d E 1 e m e n t M y L i n e
Create Circles
CenPt.X = CenX
CenPt.Y = CenY
CenPt.Z = CenZ
S e t MyCi r = Appl i c a t i o n . C r e a t e E l l i p s e E l ementZ(Nothing, CenPt,
0.25, 0.25, R o t M a t r i x )
A p p l ic a t i on . A c t i v e M o d e l R e f e r e n c e . A d d E 1 e m e n t MyCi r
S e t MyCi r = A p p l i c a t i o n . C r e a t e E l l i p s e E l e m e n t Z ( N o t h i n g , C e n P t ,
0.5, 0.5, R o t M a t r i x )
A p p l ic a t i on . A c t i v e M o d e l R e f e r e n c e . A d d E 1 e m e n t MyCi r
End S u b

The code from Mai n has been copied and pasted into the same code
module. The new pasted procedure is then renamed D r a w T a r g e t . The
goal here is to make our code more flexible, so we can draw targets
anywhere we specify. Our new procedure, D r a w T a r g e t requires us to
specify three parameters named CenX, CenY, and CenZ: We declare
them as doubles (very precise numbers). Lets take a look at how we
use it.
I Forms I 49

Sub Main0
Draw T a r g e t s
DrawTarget 0, 0, 0
DrawTarget 3, 0, 0
DrawTarget -3, 0, 0
DrawTarget 0, 3, 0
DrawTarget 0, -3, 0
End S u b

Our procedure M a i n now draws five targets. More flexible? More


powerful? Absolutely. But the coordinates are still hard-coded. This may
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? Lets
expand our program a little by introducing a graphical user interface.

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 txtL This is done in the
properties window inside VBA.
When a control is selected, we can make
changes to the controls 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 frmCh05:
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 D r a w T a r g e t procedure we just created. We need to write
some code in the C1 ic k E v e n t of the CommandButton. Double-click on
50 I Chapter 5: Modules, Forms, and Class Modules I
the button when we are designing in our project to be taken into the
We cun also C l i c k E v e n t oftheCommandButton.
get here by
right-clicking
on the button
and selecting Private Sub CormnandButtonl-Click()
View Code in DrawTarget CDbl(txtX.Text), CDbl(txtY.Text), CDbl(txtZ.Text)
End Sub
the POP-UP
menu.

You only need to enter one line of code to use both the D r a w T a r g e t
procedure and the values entered into the forms 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 dont want the
user to enter the VBA environment to run this program, so we will make
another change to the procedure named Ma in.

Sub M a i n 0
D i s p l a y the Form
frmCh05.show
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 51

The macro named


Mai n that is shown is
the procedure Main.
When it is selected,
click the Run
button.
The form is
displayed so we can
enter numbers for X, <All Standard Projects)
Y, and Z coordinates
to place our targets.
Before we continue,
lets 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 Ma in
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 Mai n and creating a
new procedure named D r a wTa r g e t . 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 Mai n to use the
Procedure named D r a w T a r g e t .
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 DrawTa r g e t (converting the values from a string to a double by using
the standard VBA CDbl function). The last step was to change the code
in Ma in to display the form.
We now have a code module and a form working together using Ma in to
display the form. When the user clicks the button, values from the form
are parameters in D r a w T a r g e t , which resides in the code module. So,
why is D r a w T a r g e t in the code module? Couldnt 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 D r a w T a r g e t as easily if
it had been placed in the forms 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 I Chapter 5: Modules, Forms, and Class Modules I
that are using code in a code module as well as procedures and functions
in a different code module, for example.
Our code is working pretty well right now but can we do anything else to
make our project more flexible and powerful? That is a good question.

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.
Thats pretty powerful and it meets our needs today. What happens,
however, if a year from now we find we want to change the targets size?
The procedure DrawTarget 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 doesnt 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.
Lets add a new class module to our project. Do this by using the VBA
menu Insert > Class Module. Name it &Target (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.
P u b l i c X As D o u b l e
P u b l i c Y As Double
P u b l i c Z As Double
I Classes I 53

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.

P u b l i c X 85 D o u b l e
P u b l i c Y As D o u b l e
P u b l i c Z As D o u b l e

Sub Draw!)
D e c l a r e FsriSJ31es
D i m N y L i n e As L i n e E l e m e n t
D i m N y C i r As EllipseElement
D i m C e n P c As P o l n t S d
D i m L i n e s t As P o l n c 3 d
D i m L i n e E n As P o l n t 3 d
D i m R O t N a t r i x 83 N a t r l x a d
Create H n r i z o n s a l L i o e
L1neSt.X = X - 1
L1neSt.Y = Y
Llne5t.Z = Z
L1neEn.X = X + I
LineEn.Y = Y
L1neEn.Z = Z
Set N y L l n e = B p p l i c B t i ~ n . C T e a t e L i n = E l = m = n t 2( N o t h i n g , L l n e S c , L l n e E n )
AppliCatiOn.ACtIveModelRefeTence.*ddEl~m~nt N y L i n e
i r e a i r vertzzai Line
Line5t.X = X
LineSt.Y = Y + 1
L1neSt.Z = Z
L1neEn.X = X
L1neEn.Y = Y - 1
L1neEn.Z = Z
Set N y L i n e = h p p l i c a t i O n . C T e a t e L i n e E l e m e n f 2 ( N o t h i n g , L i n e s t , L l n e E n )
Application.ActiveModelReference.BddEl~m~nt N y L i n e
create Circles
CenPt.X = X
CenPt.Y = Y
CenPt.Z = Z
Set N y C i r = Application.CreateEllipseElemenrZ(Nothing, C e n P t , 0 . 2 5 , 0.25, R o t N a t r i x )
Application.ActiveModelReference.BddElem~nt N y C i r
Set N y C l r = A p p l i c a t i ~ n . C ~ e ~ F e E l l ~ p ~ ~ E( Nl m ~ hml n~ gn, c C2 e n P t , 0 . 5 , 0 . 5 , R o t M a t r i x )
AppliCatiOn.ACtIveModelRefeTence.lddEl~m~nt N y C i r
End S m

And here is the code as it should be typed:

P u b l i c X As Double
P u b l i c Y As Double
P u b l i c Z As Double

Sub D r a w ( x As D o u b l e , Y As D o u b l e , Z As Double)
Declare Variables
Dim MyLine A s L i n e E l e m e n t
Dim MyCi r A s El 1 i p s e E l e m e n t
54 I Chapter 5: Modules, Forms, and Class Modules I
D i m C e n P t As P o i n t 3 d
D i m L i n e S t As P o i n t 3 d
D i m L i n e E n As P o i n t 3 d
D i m R o t M a t r i x As M a t r i x 3 d
'Create Horizontal Line
LineSt.X = X - 1
LineSt.Y = Y
LineSt.Z = Z
LineEn.X = X + 1
LineEn.Y = Y
LineEn.Z = Z
S e t MyLine = Application.CreateLineElementZ(Nothing, L i n e S t , L i n e E n )
A p p l ic a t i on . A c t i v e M o d e l R e f e r e n c e . A d d E 1 e m e n t M y L i n e
'Create Vertical Line
LineSt.X = X
LineSt.Y = Y + 1
LineSt.Z = Z
LineEn.X = X
LineEn.Y = Y - 1
LineEn.Z = Z
S e t MyLine = Application.CreateLineElementZ(Nothing, L i n e S t , L i n e E n )
A p p l ic a t i on . A c t i v e M o d e l R e f e r e n c e . A d d E 1 e m e n t M y L i n e
'Create Circles
CenPt.X = X
CenPt.Y = Y
CenPt.Z = Z
S e t MyCir Application.CreateEllipseElement2(Nothing, CenPt,
= ~

0.25, 0.25, R o t M a t r i x )
A p p l ic a t i on . A c t i v e M o d e l R e f e r e n c e . A d d E 1 e m e n t MyCi r
S e t MyCir = Application.CreateEllipseElementZ(Nothing, CenPt, -

0.5, 0.5, R o t M a t r i x )
A p p l ic a t i on . A c t i v e M o d e l R e f e r e n c e . A d d E 1 e m e n t MyCi r
End S u b
I Procedures and Functions I 55

Once everything is in place, we can use it as follows:

Private Sub CommandButtonl-Click()


DrawTarget CDbl(txtX.Text), CDbl(txtY.Text), CDbl(txtZ.Text)
Dim MyTarget As New clsTarget
MyTarget.X = CDbl(txtX.Text)
MyTarget.Y = CDbl(txtY.Text)
MyTarget.2 = CDbl(txt2.Text)
MyTarget.Draw
End Sub

Instead of using the D r a wTa r ge t procedure we previously created, we can


use the &Target class. Comment out the DrawTarget line of code.
Next declare a variable as a New clsTarget then set the X, Y, and Z
properties of the object and invoke the Draw method.
Class modules are often considered reserved for advanced programmers
but this doesnt need to be the case. As we see here, classes can be
implemented very easily and simply. We will discuss classes in greater
detail in a later chapter.

PROCEDURES AND FUNCTIONS


Modules, forms, and classes each use procedures and functions.
Procedures are declared with the Sub keyword and functions are
declared with the Function keyword.
Lets look at a few procedures and functions.

Sub D r a w C i rcl e ( )
Declare Variables
D i m MyCi r As E l 1 i p s e E l e m e n t
D i m C e n P t As P o i n t 3 d
D i m R o t M a t r i x As M a t r i x 3 d
Create C i r c l e
CenPt.X = 0
CenPt.Y = 0
CenPt.Z = 0
S e t MyCir = Application.CreateEllipseElement2(Nothing, CenPt,
0.25, 0.25, R o t M a t r i x )
A p p l i c a t i o n . A c t i v e M o d e 1 R e f e r e n c e . A d d E l e m e n t MyCi r
56 I Chapter 5: Modules, Forms, and Class Modules I
End Sub

D r a w C i rcl e draws a circle at (0, 0,O) with a radius of 0.25. It can be run
by itself without the any other procedure or function.

Sub D r a w C i r c l e 2 ( Radi us A s D o u b l e )
Declare Variables
D i m MyCir As E l l i p s e E l e m e n t
D i m CenPt As P o i n t 3 d
D i m R o t M a t r i x As M a t r i x 3 d
Create C i r c l e
CenPt.X = 0
CenPt.Y = 0
CenPt.Z 0 =

Set MyCir = Application.CreateEllipseElementZ(Nothing, CenPt, -

Radius, Radius, R o t M a t r i x )
Appl ic a t i on . A c t i veModel Reference.AddE1 ement MyCi r
End Sub

D r a w C i rcl e2 is a procedure with a single required parameter.


D r a w C i rcl e2 cannot be run by itself - it requires another procedure or
function to run it. When it is called by another function or procedure,
the required parameter Radius must be supplied like this:
D r a w C i r c l e2 1 . 5

Sub D r a w C i r c l e 3 ( x As D o u b l e , Y As D o u b l e , Z As D o u b l e , ~

O p t i o n a l Radius As D o u b l e = 1.25)
Declare Variables
D i m MyCir As E l l i p s e E l e m e n t
D i m CenPt As P o i n t 3 d
D i m R o t M a t r i x As M a t r i x 3 d
Create C i r c l e
CenPt.X = X
CenPt.Y = Y
CenPt.Z = Z
Set MyCir = Application.CreateEllipseElernentZ(Nothing, CenPt,
Radius, Radius, R o t M a t r i x )
Appl ic a t i on . A c t i veModel Reference.AddE1 ement MyCi r
End Sub
I Proceduresand Functions I 57

0 rawCi r c l e3 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 T e s t D r a w C i r c l e3( 1
D r a w C i r c l e 3 2.25, 2.25, 0
D r a w C i r c l e 3 2.25, 2.25, 0, 1.125
End Sub

The first time we call DrawCircle3 we do not provide the optional


parameter. The second time we call it we provide a radius value of 1.125.
The first circle will be drawn with a radius of 1.25 (the default value) and
the second will be drawn with a radius of 1.125.
Sub T e s t D r a w C i r c l e 3 0
Once an Drawcircle3 2.25, 2.25, 0
Optional Drawcircle3 2.25, 2.25, 0, 1.125

Parameter is End Sub


declared in
the
Procedure, As we call functions and procedures, VBA displays a tip that shows us
any the parameters for the function or procedure that we are calling. Notice
parameters how the radius parameter is enclosed in square brackets. The square
afrer it must
also he
brackets tell us that Radius is an optional parameter. We are also
optional. shown the value of the optional parameter that will be used if we do not
supply a value.
Another type of parameter that can be declared in a procedure or
function is called ParamArray. A ParamArray must be the last
parameter declared, because when we supply a value or values to the
parameter in code, we can supply any number of values for the
parameter. Here is an example of how it is declared and used in code:

Sub D r a w C i r c l e 4 ( x As D o u b l e , Y As D o u b l e , Z As D o u b l e ,
P a r a m A r r a y R a d i i 0 As V a r i a n t )
Declare Variables
D i m MyCi r As E l 1 i p s e E l e m e n t
D i m C e n P t As P o i n t 3 d
D i m R o t M a t r i x As M a t r i x 3 d
D i m I As Long
Create Circles
CenPt.X = X
58 I Chapter 5: Modules, Forms, and Class Modules I
CenPt.Y = Y
CenPt.Z = Z
For I = LBound(Radii To U B o u n d ( R a d i i
S e t MyCir Application.CreateEllipseElementZ(Nothing, CenPt,
= -

Radii ( I1 , Radii ( I1 , RotMatrix)


A p p l ic a t i o n . A c t i v e M o d e l R e f e r e n c e . A d d E 1 e m e n t MyCi r
Next I
End Sub

We dont know how many radius values w ill 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 T e s t D r a w C i r c l e4( )
D r a w C i r c l e 4 1, 1, 0 , 0 . 2 5 , 0.5, 0.75, 1, 1 . 2 5 , 1.5
End Sub

We provide an X of 1, a Y of 1, and a Z of 0. Then we begin providing


radius values. After the code is run, we have six new circles in our
Microstation design file.
Here are the six circles created by
T e s t D r a w C i r c l 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,
i
the others must be called by other
procedures or functions.
Speaking of functions, lets examine them in detail.

F u n c t i o n P i 0 As D o u b l e
Pi = Atn(1) * 4
End F u n c t i o n

Here is a function named P i . It does not accept any parameters and the
type of value it returns is a Double.
We specify what value is to be returned by assigning the return value to
the name of the function.
I Procedures and Functions I 59

This function, P i , can be used now wherever we need the value of Pi.
The procedure DrawCi r c l e 3 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 P i function we just created.

Sub T e s t P i 0
D i m C i r c l e A r e a As D o u b l e
D i m C i r c l e R a d i u s As D o u b l e
CircleArea = 3.5
C i r c l e R a d i us = Sqr(Ci rcleArea / P i )
DrawCi r c l e 3 2 . 5 , 2.5, 0 , C i r c l eRadi us
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 D r a wC ir c 1 e3.
The function P i we just created does not have any parameters. It does
not need them because the calculation is always the same. Lets 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).

F u n c t i o n R T D ( A n g l e 1 n R a d i a n s As D o u b l e ) As D o u b l e
RTD = AngleInRadians * 180 / P i
End F u n c t i o n

F u n c t i o n D T R ( A n g l e 1 n D e g r e e s As D o u b l e ) As D o u b l e
DTR = AngleInDegrees * P i / 180
End F u n c t i o n

These two functions perform calculations that are very common to


those of us who use Microstation. They are shown here for instructional
purposes only because Microstations VBA implementation has a
function named D e g r e e s that converts radians to degrees and a function
named Ra d ia n s that converts degrees to radians.
The functions DTR and RTD (as well as the functions D e g r e e s and R a d i a n s )
have one required parameter. Here is how we use them:
Sub D r a w A r c l ( )
D i m MyArc As A r c E l e m e n t
D i m C e n P t As P o i n t 3 d
D i m R o t M a t r i x As M a t r i x 3 d
60 I Chapter 5: Modules, Forms, and Class Modules I
S e t MyArc = Application.CreateArcElementZ(Nothing, C e n P t , 1 . 5 , -

1.5, R o t M a t r i x , DTR(45). DTR(90))


Application.ActiveModelReference.AddE1ement MyArc
End Sub

C r e a t e A r c E l ernent2 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 dont 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 w ill 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. Heres what it looks like:

F u n c t i o n P o l a r P o i n t ( X As D o u b l e , Y As D o u b l e , Z As D o u b l e , -

The A n g l e As D o u b l e , D i s t a n c e As D o u b l e ) As V a r i a n t
underscore D i m XChange As D o u b l e
(J character D i m YChange As D o u b l e
allows one XChange = Cos(Ang1e) * Distance
line ofcode to YChange = Sin(Ang1e) * Distance
span multiple
D i m P P o i n t ( 0 To 2) As D o u b l e
lines.
PPoint(0) = X + XChange
PPoint(1) = Y + YChange
PPoint(2) = Z
Polarpoint = PPoint
End F u n c t i o n
I Procedures and Functions I 61

The Po 1 a r P o in t 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. Heres one way to test the P o l a r P o i n t
function.

Sub TestPolarPointO
D i m S t a r t C e n As P o i n t 3 d
D i m C e n P t As P o i n t 3 d
D i m R o t M a t r i x As M a t r i x 3 d
D i m X As V a r i a n t
StartCen.X = 2
StartCen.Y = 2
StartCen.Z = 0
S e t MyCir = Application.CreateEllipseElement2(Nothing, -
S t a r t C e n , 1, 1, R o t M a t r i x )
Application.ActiveModelReference.AddE1ement MyCir
D i m R o t A n g l e As D o u b l e
For RotAngle = 0 To 3 6 0 S t e p 3 0
X = PolarPoint(StartCen.X, StartCen.Y, StartCen.Z, ~

D T R ( R o t A n g l e ) , 4)
CenPt.X = X(0)
CenPt.Y = X(1)
CenPt.Z = X(2)
S e t MyCir = Application.CreateEllipseElement2(Nothing, -
C e n P t , 1, 1, R o t M a t r i x )
Application.ActiveModelReference.AddElement MyCir
Next RotAngl e
End Sub
62 I Chapter 5: Modules, Forms, and Class Modules I
What do we get when we run T e s t P o l ar P o i n t ?

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
PolarPoint function and make use of this type.

F u n c t i o n P o l a r P o i n t 2 ( x As D o u b l e , Y As D o u b l e , Z As D o u b l e , -
A n g l e As D o u b l e , D i s t a n c e As D o u b l e ) As P o i n t 3 d
D i m XChange As D o u b l e
D i m YChange As D o u b l e
XChange = Cos(Ang1e) * Distance
YChange = Sin(Ang1e) * Distance
D i m P P o i n t ( 0 To 2 ) As D o u b l e
PolarPoint2.X = X + XChange
PolarPoint2.Y = Y + YChange
PolarPoint2.Z = Z
End F u n c t i o n

Instead of returning an array as in the previous example, we are


returning a Point3d type. Here is an example that uses the Po 1 a r Po in t 2
function:

Sub T e s t P o l a r P o i n t 2 ( )
D i m S t a r t C e n As P o i n t 3 d
D i m C e n P t As P o i n t 3 d
D i m R o t M a t r i x As M a t r i x 3 d
D i m X As V a r i a n t
StartCen.X = 2
I Procedures and Functions I 63

StartCen.Y = 2
StartCen.Z = 0
S e t MyCir = Application.CreateEllipseElement2(Nothing, ~

S t a r t C e n , 1, 1, R o t M a t r i x )
A p p l i c a t i o n . A c t i v e M o d e 1 R e f e r e n c e . A d d E l e m e n t MyCi r
D i m R o t A n g l e As D o u b l e
For RotAngle = 0 To 3 6 0 S t e p 3 0
CenPt = PolarPointZ(StartCen.X, StartCen.Y, StartCen.Z, ~

D T R ( R o t A n g l e ) , 4)
S e t MyCir = Application.CreateEllipseElement2(Nothing, ~

C e n P t , 1, 1, R o t M a t r i x )
A p p l i c a t i o n . A c t i v e M o d e 1 R e f e r e n c e . A d d E l e m e n t MyCi r
Next RotAngl e
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.

F u n c t i o n GetExcel WS() As O b j e c t
D i m E x c e l A p p As O b j e c t
Set ExcelApp = Getobject(, "Excel . A p p l i c a t i o n " )
S e t GetExcelWS = ExcelApp.activesheet
End F u n c t i o 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 TestGetExcel WS()


D i m MyWS As O b j e c t
D i m C e l l l As D o u b l e
D i m C e l l 2 As D o u b l e
D i m C e l l 3 As D o u b l e
S e t MyWS = GetExcelWS
Celll = MyWS.Range("B2")
C e 112 = My W S . Ra n g e ( " C 2 " )
C e 1 13 = My W S . R a n g e ( " D 2 " )
End Sub
64 I Chapter 5: Modules, Forms, and Class Modules I
This procedure gets the values of three cells in Excel. It really is very easy
to get data from or write data to Excel. We will discuss more on working
with Microsoft Excel later in this book.

ByVal and ByRef


We have seen how we can provide parameters when we call procedures
and functions. By default, values are passed by reference. The other way
values can be passed is by value. What do these mean?

Sub GetThreeVals(x As D o u b l e , Y As D o u b l e , Z A s D o u b l e )
X = l
Y = 2
z = 3
End Sub

This procedure accepts three parameters. Inside the code, we use the
parameters 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 TestGetThreeValsO
D i m A As Double
D i m B As Double
D i m C As Double
A = 100
B = 200
C = 300
GetThreeVals A , B, C
End Sub

Here we have variables A, B, and C. We assign values of 100, 200, and


300 respectively. Then we use these variables (A, B, and C) when we call
G e t T h r e e V a l s. Since the procedure G e t T h r e e V a l s has its parameters
declared without the keyword ByVal, the values are passed into the
procedure ByRef. ByRef means the values of the parameters may be
modified inside the procedure. And if they are modified in the
procedure, the variables will maintain these values outside of the
procedure. So, before the line of code GetThreeVals A, B, C is
executed, the values of A, B, and C are 100, 200, and 300. After
G e t T h r e e V a l s is executed, the values of A, B, and C are 1,2, and 3.
I Procedures and Functions I 65

GetThreeVal s changes the values of the parameters that are passed in.
This can be a powerful feature if it is used correctly. It can also cause a
great deal of confusion if it is not understood. Suddenly, variables that
were holding one value could hold another value.
If we do not want a function or procedure to change the values of the
variables passed as parameters, there are a couple of ways we can do this.
The first technique requires discipline on our part. The second
technique is a more definite method.

Sub G e t T h r e e V a l s P ( X As D o u b l e , Y As D o u b l e , Z A s D o u b l e )
Dim dblX As Double
Dim dblY As Double
Dim d b l Z As Double
dblX = X
dblY = Y
dblZ = Z
dblX = 1
dblY = 2
dblZ = 3
End Sub

Instead of manipulating the parameters directly, we place the values of


the parameters into variables declared inside the procedure. Then we
manipulate these local variables. This keeps us from changing the
parameters.
Another way to maintain the integrity of the parameters passed into our
functions and procedures is to declare them explicitly as ByVal.

Sub G e t T h r e e V a l s 3 ( B y V a l X As D o u b l e , ByVal Y A s D o u b l e , -
ByVal Z A s D o u b l e )
X = l
Y = 2
z = 3
End Sub

Taking the additional step of declaring a parameter as ByVal guarantees


the integrity of the parameters.
66 I Chapter 5: Modules, Forms, and Class Modules I

Declaring Variables
Variables are used extensively throughout our code. Variables are
declared with a name and a type. We will learn more about this in the
next chapter. What is important to understand now is that variables
have a scope. There is a pre-determined amount of time when a variable
can be used. The variables scope depends on where it is declared and
what keywords (if any) are used when it is declared. There are two places
where variables can be declared. One place is inside the procedures and
functions in which they will be used. We have seen numerous examples
of this so far. The other place we declare variables is in the General
Declarations area of code modules, forms, and class modules.

D i m S t a r t P o i n t X A s Double
P r i v a t e S t a r t P o i n t Y A s Double
P u b l i c S t a r t P o i n t Z A s Double

In the General Declarations area of this code module, I declared three


variables as the same type (as doubles) but used different keywords to
declare them: Dim, Private, and Public.

D i m S t a r t P o i n t X as Double

Declaring a variable with Dim in the General Declarations area of a


code module or form code area means the variable is only available for
use from within that module, form, or class module. StartPointX was
declared by using the Dim keyword so, again, it can only be used from
within the module or form in which it is declared.
Private has the same effect as using Dim: You can use the variable
within any function or procedure in the code area in which it is
declared. One function can set its value and another function in the
same module, form, or class can read the value.
Publicvariable declarations behave differently depending on where the
declarations are made.
I Review I 67

Forms - Publicly declared variables are in scope when the form is in


scope (usually only when it is displayed). Other areas of a project can
access the variable through the forms name. For example,

UserForml.TestVariable = 4.5
We can use the variable Testvariable only by addressing it through the
form and the form must be in scope for this to work.
Modules - Publicly declared variables are in scope for all areas within
the same project.
Classes - Publicly declared variables are seen as read/write properties
for the class.

Option Explicit
By default, if we attempt to use a
variable that is not declared, it
inherits the type of Variant: We
can force ourselves to declare
variables by using Option
Explicit in the General
Declarations area of modules,
forms, and classes.
In this example, we have declared Option
Explicit in the General Declarations area.
When we attempt to run the macro test shown
above we get an error.
To avoid this error, we need to declare X as a e
double, integer, or long. More on variable types
in the next chapter.

REVIEW
Write code as procedures, functions, or inside user form events.
In procedures and functions utilize required and optional
parameters.
B In functions you can return values, arrays, types, and objects.
I Chapter 5: Modules, Forms, and Class Modules I
In procedures and functions you can make changes to the
variables passed into them as parameters if the parameters are
declared as ByRef.Declare a parameter as ByVal to keep the
variables value from changing.
Declare variables in procedures, functions, and events or in the
General Declarations area. The scope of these variables depends
on where they are declared and what keywords accompany the
declaration.
Variables

1+N+3=7
What is N?N is a variable. In the above equation it represents a number.
If we were to solve for N we would get a value of 3.
Learning Microstation VBA & N & Easy.
What is N? N is a variable. In the above
equation it represents a string of characters.
What string of characters does it represent?
Is: E

In this Chapter:
Standard VBA Variable Trpes
Microstation-Specific Variable Trpes
Assigning Values and Setting Objects
Arrays
Constants
Variable Names
Option Explicit
Using Variables

69
70 I Chapter 6: Variables I

TYPES
STANDARDVBA VARIABLE
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 object a variable will
be representing. Since we know this, we specify what type of variable we
will use by declaring it.

D i m N as I n t e g e r

N = 7 - 3 - 1

Here, we declare the variable N as an integer. This means it will be a


whole number between -32,768 and 32,767.

D i m N As S t r i n g
N = "IS"

MsgBox " L e a r n i n g M i c r o s t a t i o n V B A " & N & " Easy."

Here we declare N as a string. A string is a group of characters. After a


variable is assigned a value, you can use it in the place of a number, text,
or some other type of value or object.
We will use variables extensively throughout this book. Let's examine
some of the more common types of variables available to us.

Integer
D i m PageNumber a s I n t e g e r
PageNumber = 2

We said that an integer is a whole number between -32,768 and 32,767.


If we need a variable to hold a value greater than or less than the range of
an integer, we must declare it as something different.

Long
D i m M y S a l a r y as Long

MySalaray = 123456

A long is a whole number between -2,147,483,648 and 2,147,483,647.


These numbers are much larger than those in the range of an integer. It
I Standard VBA Variable Types I 71

requires more memory to allow for this greater range of numbers so we


should only use it when we need it.

Double
D i m HoursToLearnVBA as D o u b l e
HoursToLearnVBA = 36.25

A double is also called a double precision floating 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, V a r i a b 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 VariableTestCO
D i m N As Double
N = 1.23456789012346
N = 12.3456789012346
N = 123.456789012346
N = 1234.56789012346
N = 12345.6789012346
N = 123456.789012346
N = 1234567.89012346
N = 12345678.9012346
N = 123456789.012346
N = 1234567890.12346
N = 12345678901.2346
72 I Chapter 6: Variables I
N = 123456789012.346
N = 1234567890123.46
N = 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
D i m ICanLearnThis as Boolean

ICanLearnThis = True

A Boolean data type can hold one of two values: True or False.

Date
D i m XMReleaseDate as Date
XMReleaseDate = 5/19/2006 8:OO:OO AM

A Date data type holds a Date/Time value.

String
D i m MyLevelName a s S t r i n g
M y L e v e l Name = u t i 1E l e c t r i c i t y

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
D i m M y E x c e l A p p as O b j e c t

S e t MyExcelApp = Getobject(, Excel . A p p l i c a t i o n )

Object type variables point to objects. The variable MyExcelApp, for


example, could point to an instance of Microsoft Excel, an application.
Microsoft Excel is an object with specific properties, methods, and
I MicroStation-SpecificVariable Types I 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
D i m P o i n t A r r a y as V a r i a n t

Variables declared as a variant can hold any type of value, point to any
type of object, or even contain an array of values.

VARIABLE
MICROSTATION-SPECIFIC TYPES
The variable types we have discussed are standard VBA variable types.
They can be used in Microstation VBA, in Excel VBA, in Word VBA, or
in Access VBA. Lets consider some of the variable types specific to
Microstation that we will regularly use.

A ppIicat ion
D i m MSApp As A p p l i c a t i o n
S e t MSApp = Application

The application variable type points to the Microstation application. It


is the top level object when dealing with Microstation. A few of the
things we can do from a variable declared and set to the Microstation
application are:
Get the ActiveDesignFile property
Get the ActiveModelReferenceproperty
Get the Activesettings object and its properties
Get the ExecutingVBProject object and its properties
Get the UserName property
Get the left, top, width, and height properties
74 I Chapter 6: Variables I

DesignFile
D i m MyDGN As D e s i g n F i l e
S e t MyDGN = Application.ActiveDesignFile
The DesignFile object refers to a Microstation DGN file. Top-level DGN
properties and collections are available to us via the DesignFile object.
Get and set the Author, Client, Comments, Company,
Keywords, Manager, Subject, and Title Properties
Get the FormatMajorVersion and FormatMinorVersion
properties
Get the Levels collection
Get the Models collection
Get the Name and Path properties

ModelReference
D i m MyModel As M o d e l R e f e r e n c e
S e t MyModel = Appl i c a t i o n . A c t i v e M o d e 1 Reference

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
D i m M y L e v e l As L e v e l
S e t MyLevel = A p p l i c a t i o n . A c t i v e D e s i g n F i 1e . L e v e l s ( l )

Levels allow us to divide our designs into groups of objects. We usually


group our objects based on their specific type of geometry or
annotation. Road centerlines may be placed on one level, Lot numbers
on another, and title block lines on another, etc. Here are a few of the
properties we can get and set from the level object:
Description
ElementColor
ElementLineStyle
I Microstation-SpecificVariable Types I 75

ElementLineWeight
IsActive
IsDisplayed
IsFrozen
El IsLocked
Name
Number
Plot

LineElement
D i m M y L i n e As L i n e E l e m e n t

Set MyLine = Application.CreateLineElementZ(Nothing,


Point3dFromXYZ(O, 0 , O ) , Point3dFromXYZ(4, 5 , 6))
A p p l ic a t i o n . A c t i veModel R e f e r e n c e . A d d E l e m e n t M y L i n e

A LineElement is created with a start point and an end point. After it is


created, we can add it to our model.

EllipseElement
D i m M y C i r c l e As E l l i p s e E l e m e n t
D i m R o t M a t r i x As M a t r i x 3 d
Set MyCircle = CreateEllipseElementZ(Nothing, -

Point3dFromXYZ(O, 0 , O ) , 1 . 5 , 1.5, RotMatrix)


A p p l i c a t i o n . A c t i v e M o d e 1 R e f e r e n c e . A d d E l e m e n t MyCi r c l e

Lines, circles, and arcs form the basis of much of the geometry found in
our Microstation files. From Microstations perspective, circles are
essentially ellipses with equal major and minor radii. The code shown
above draws a circle centered at (0, 0,O) with a radius of 1.5.

ArcElement
D i m MyArc As A r c E l e m e n t
D i m R o t M a t r i x As M a t r i x 3 d

S e t MyArc = CreateArcElementZ(Nothing, -

Point3dFromXYZ(O, 0 , O ) , 1.75, 1.75,


76 I Chapter 6: Variables I
RotMatrix, Radians(45). Radians(90))
Application.ActiveModelReference.AddElement MyArc

We are given several ways to create a new LineElement, EllipseElement,


and ArcElement. In this example, we create a new ArcElement by
providing a center point, major and minor radii, a start angle, and a
sweep angle.

Text Element
D i m M y T e x t As T e x t E l e m e n t
D i m R o t M a t r i x As M a t r i x 3 d
S e t MyText = C r e a t e T e x t E l e m e n t l ( N o t h i n g , " M i c r o S t a t i on V B A " ,

P o i n t 3 d F r o m X Y Z ( O , 0 , 0). R o t M a t r i x )
Application.ActiveModelReference.AddE1ement 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.

ASSIGNINGVALUES AND SETTING OBJECTS


Value-type variables and object-type variables are declared similarly.
When giving the variables values or setting them to objects, there is one
major difference.
D i m LevelName As S t r i n g

L e v e l Name = "Easement"
D i m E a s e m e n t L e v e l As L e v e l

S e t EasementLevel = -
A c t i v e D e s i g n F i l e . A d d N e w L e v e 1 ( L e v e l Name)

Here we have two 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

object. We only use Set when we are setting a variable to an object.


After it is set to an object we can address it by its name without using
Set.

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.
D i m S t a r t P o i n t ( 0 t o 2 ) as D o u b l e
StartPoint(0) = 4.5
StartPoint(1) = 5.6
StartPoint(2) = 6.7

In this example, we declared a variable as an array with three elements


numbered 0, 1, and 2. We can address the elements individually by
specifying their index within the array.
In the next example, I created an array where each Point3D type has an
X property, a Y property, and a Z property. Notice how I addressed each
element in the array by its index (0 and 1) and then addressed the X, Y,
and Z properties.
Sub ArrayTestA()
D i m M y V e r t i c i e s ( 0 To 1) A s P o i n t 3 d
D i m M y L i n e As L i n e E l e m e n t

MyVerticies(O).X = 1
MyVerticies(O).Y = 2
MyVerticies(O).Z = 3
MyVerticies(l).X = 4
MyVerticies(l).Y = 5
MyVerticies(l).Z = 6
S e t MyLi ne = C r e a t e L i neEl e m e n t l ( N o t h i ng, M y V e r t ic i es)
ActiveModel Reference.AddElement MyLine
End S u b
78 I Chapter 6: Variables I

CONSTANTS
A constant is similar to a variable with one significant difference: a
constant value does not change.
C o n s t PI As Double = 3.14159

You can declare constants as public in the General Declarations area of a


code module, as shown above, from within individual procedures and
functions. Constants are useful any time you need a value that does not
change. For example, if you are writing a program that labels line lengths
in a design file, you could specify a constant for the distance the text is to
be offset from the line. A constant can also provide a units conversion
factor, such as from inches to cubits.
Another reason to use a constant is for calculations that make routine
references to specific values, such as a ShimWidth value in multiple
calculations. Instead of using a value of 0.6 when we make the
calculations, we can declare a constant with a name of Shimwidth and
assign it a constant value of 0.6. This makes our code easier to read and
allows us to change our Shimwidth value in only one place (where the
constant is declared) instead of wherever the value is used.

NAMES
VARIABLE
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.
Variables must begin with an alpha character (A through Z).
Variable names cannot contain spaces.
Name characters are A-Z, 0-9, and - (underscore).
Variable names must be 255 characters or less.
Variable names cannot be keywords (such as Dim,New,Left,
Right,Form,Public).
Letters used in variable names can be uppercase or lowercase.
I Variable Names I 79

Based on the rules already identified, here are a few variable declarations
that work:
D i m m y L i n e As L i n e E l e m e n t
D i m t x t e M y T e x t As T e x t E l e m e n t

D i m s t r N a m e As S t r i n g
D i m d b l S t a r t X As D o u b l e
D i m intLevelNumber As I n t e g e r

D i m p t 3 d S t a r t P o i n t As P o i n t 3 d

Each of the declarations shown above are legitimate variable


declarations. They follow the rules. The first, myLine, is slightly different
than the others. Each of the other declared variables begins with
characters that identify the type of variable. strName says the variable
type is a string. dblStartX says we are working with a double type
variable.
It is important to know if a project requires using variable naming
conventions. A naming convention is an additional set of rules on how
to name variables. For example, one convention may state that each
variable name begin with three characters followed by an underscore (-)
character, then a name consisting of no more than seven characters.
Another convention may not use an underscore. Yet another convention
may require that the scope of the variable be identified inside the
variables name.
As mentioned, many pages have been devoted to the topic of variable
naming conventions, so we will not spend much time here on the
subject. You should understand that naming a variable myLine or
IineMyLine or line123 does not cause your program to work any
differently than naming it elemline-LineA.
Naming conventions can extend beyond variable names. Procedure
names, function names, and control names can also be within the scope
of a naming convention.
Here is a link to a web page that discusses variable naming conventions:
http://msdn.microsoft.com/library/en-us/modcore/html/
deconVariab1eNames.asp
Another way to become familiar with naming conventions is to search
online for variable naming convention or Hungarian Notation.
80 I Chapter 6: Variables I

Case Sensitivity
Consider the following variable declarations:
D i m myLine As LineElement

D i m M Y l i n e As L i n e E l e m e n t

Since VBA is not concerned with capitalization in variable names, the


two variables declared above are the same. When we use a variable
inside VBA, VBA automatically changes the capitalization to that used
in the declaration. Some programmers use this to make sure they do not
introduce typos into their code. They may always use a capital letter
somewhere in the variable name when they declare it and then type all
lower-case when they use it. When a line of code is complete and the
cursor is moved to the next line of code, VBA automatically updates the
capitalization of the variable that had been typed in lowercase.

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 owhatafooliam: One way we can
make sure we declare our variables is to use Option Explicit in the
I Using Variables I 81

General Declarations area of our modules. Another way is to go to the


VBA menu Tools > Options.

OK

Checking the Require Variable Declaration button causes VBA to enter


Option Explicit for us.

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 V a r i a b l e T e s t D O
D i m MySalary A s Double
D i m MyHourly A s Double
MySalary = 1234567
MyHourly = MySalary / 52 / 40

MsgBox My Hourly R a t e i s & FormatCurrency(MyHourly, ~

2, v b f a l s e , v b f a l s e , vbTrue)
End Sub

Here we have two variables. One of them (MySalary)


is given a value of 1234567. We then use MySalary to
calculate MyHourly. We then use the standard VBA
function Formatcurrency to convert the variable
MyHourly to a two-decimal place currency value
82 I Chapter 6: Variables I
and concatenate My Hourly Rate is with the result of the
Format C u r rency 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.
7 Working With Text

We work with text every day. This book is composed of text: words,
phrases, sentences, paragraphs. The ability to work with text is
invaluable in our programming.
Recall that the type of variable that deals with text is a String.

Sub TextWorkOl()
D i m B o o k T i t l e As S t r i n g
B o o k T i t l e = L e a r n i n g M i c r o s t a t i o n VBA
MsgBox U C a s e ( B o o k T i t 1 e )
MsgBox L C a s e ( B o o k T i t 1 e )
MsgBox L e f t ( B o o k T i t l e , 12)
MsgBox R i g h t ( B o o k T i t l e , 12)
End S u b
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.

83
84 I Chapter 7: Working With Text I

VBA STRINGFUNCTIONS
Let's take a look at each of the VBA functions that deal with text
(Strings) one-by-one.

UCase
Function UCase(Stri ng)
The U Ca s e function converts the supplied string to upper case.

Sub TextWorkOP(
D i m s t r N e w L e v e l As S t r i n g
s t r N e w L e v e l = I n p u t B o x ( " E n t e r New L e v e l N a m e : " )
strNewLevel = UCase(strNewLeve1
A p p l ic a t i on . A c t i v e D e s i g n F i 1 e.AddNewLeve1 s t r N e w L e v e 1
End Sub

sidewalk

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 All Levels
Filters
(AddNewLevel) to the active design
file.

Function LCase(Stri ng)


The LCase function converts the supplied string to lower case.

Sub TextWork03(
D e b u g . P r i n t LCase("LCase Lowers C a p i t a l L e t t e r s . " )
End Sub
I VBA String Functions I 85

Debug.Print
is used to lcase lowers c a p i t a l l e t t e r s .
place text in
the
Immediate
Window. It is In this example we used text directly in the function instead of assigning
often used to the text to a variable.
display text to
aid in
debugging StrConv
our
F u n c t i o n S t r C o n v ( S t r i n g , C o n v e r s i o n As V b S t r C o n v , -
applications.
To view the [ L o c a l e I D As L o n g ] )
lmmediate
StrConv is used to convert the provided string through a variety of
Window, go
to the VBA parameters. The constant most used with StrConv is 'vbProperCase'.
menu View > Sub T e x t W o r k 0 4 ( )
Immediate D i m B o o k T i t l e As S t r i n g
Window. B o o k T i t l e = " l e a r n i n g m i c r o s t a t i o n vba"
MsgBox S t r C o n v ( B o o k T i t l e , vbProperCase)
End Sub

This example uses the vbProperCase constant


to capitalize the first letter of each word.

WeekDayName, WeekDayNumber
F u n c t i o n We e k d a y N a m e(W eekday As L o n g , -
[ A b b r e v i a t e As B o o l e a n = F a l s e ] , -
C F i r s t D a y O f W e e k A s VbDayOfWeek = vbUseSystemDayOfWeek1) -
As S t r i n g

Each day of the week (Sunday through Saturday) has a number assigned
to it. The WeekdayName function takes that number and converts it to the
day's name.
Sub T e x t W o r k 0 5 ( )
D i m TodaysDate A s Dat e
D i m WeekDayNumber A s Long
TodaysDate = N o w
WeekDayNumber = Weekday(T0daysDate)
MsgBox WeekdayName(WeekDayNumber)
MsgBox WeekdayName(WeekDayNumber, T r u e )
End Sub
86 I Chapter 7: Working With Text I
The first parameter supplied to
WeekdayName is the day number.
The second parameter,
'Abbreviate', is optional with a
default of false. When we P

supply a value of true, the


WeekDayName is abbreviated.

MonthName
F u n c t i o n MonthName(Month As Long, -
[ A b b r e v i a t e As B o o l e a n = F a l s e ] ) As S t r i n g
The MonthName function is similar to the
WeekdayName function but as the name
implies, it returns the name of the month January
instead of the name of the day. February
March
April
Wau
Sub TextWork05B() June
D i m MonthNum As L o n g July
August
F o r MonthNum = 1 To 1 2 September
D e b u g . P r i n t MonthName(MonthNum1 October
November
N e x t MonthNum December
End Sub

LTrim, RTrim, Trim


Function LTrim(String)
Function RTrim(Stri ng)
Function T r i m ( S t r i ng)

Use the Tr im functions to remove spaces from the beginning, end, and
both beginning and end of a string.
Sub TextWorkOG( 1
D i m S t r i n g T o T r i m As S t r i n g
S t r i n g T o T r i m = " T r i m F u n c t i o n s T r i m Space C h a r a c t e r s . "

Debug. P r in t L T r im ( S t r in g T o T r im 1
Debug. P r in t RTr im ( S t r in g T o T r im 1
Debug. P r in t T r im ( S t r in g T o T r im 1
End Sub
I VBA String Functions I 87

StrComp
Function StrComp(String1, String2, -
[Compare A s VbCompareMethod = vbBinaryCompare1)
The need to compare two pieces of text is common. Is "Sidewalk" the
same as "SIDEWALK"? Not always.

Sub TextWork07()
D i m s t r N e w L e v e 1 As S t r i n g
D i m 1 v l E x i s t L e v e l As L e v e l
s t r N e w L e v e 1 = I n p u t B o x ( " E n t e r New L e v e l Name:")
F o r Each l v l E x i s t L e v e l I n A p p l ication.ActiveDesignFile. L e v e l s
I f S t r C o m p ( s t r N e w L e v e 1 , 1 v l E x i s t L e v e l .Name,
~

v b T e x t C o m p a r e ) = 0 Then
MsgBox " T h e l e v e l " & s t r N e w L e v e 1 & " a l r e a d y e x i s t s . "
E x i t Sub
End I f
Next
Application.ActiveDesignFile.AddNewLeve1 s t r N e w L e v e 1
End Sub

This procedure asks the user for a new level name. It compares the
newly-entered name with the name of each existing level name. If it
finds a match, a MessageBox displays and we exit the procedure.
StrComp allows us to specify how the provided text is to be compared. In
the above example, the constant 'vbTextCompare' returns a value of zero
(0) when the characters are the same, independent of the capitalization.
With 'vbTextCompare', "SWalk" and "swalk" are the same.

Sub TextWork08()
Debug. P r i n t StrComp("SWa1 k " , "swal k", vbTextCompare)
Debug. P r i n t StrComp("swa1 k " , "SWal k", vbTextCompare)
Debug.Print StrComp("SWa1 k " , "swal k", vbBinaryCompare)
Debug.Print StrComp("swa1 k " , "SWal k", vbBinaryCompare)
End Sub
88 I Chapter 7: Working With Text I

0
0
-1
1

StrComp 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 Bubbl e S o r t ( 1
D i m s t r N m s ( 0 To 7 ) As S t r i n g
strNms(0) = " J e r r y "
strNms(1) = "Candice"
strNms(2) = "Brandon"
strNms(3) = "Kyle"
strNms(4) = "Benjamin"
strNms(5) = "Jacob"
strNms(6) = "Nathan"
strNms(7) = " O l i v i a "
D i m Madechange As B o o l e a n
D i m tmpName As S t r i n g
D i m I A s Long
Madechange = T r u e
W h i l e Madechange = T r u e
Madechange = F a l s e
F o r I = L B o u n d ( s t r N r n s ) To U B o u n d ( s t r N m s ) - 1
I f S t r C o r n p ( s t r N r n s ( 1 ) . s t r N m s ( 1 + l), -
V b B i n a r y C o m p a r e ) = 1 Then
trnpNarne = s t r N r n s ( 1 )
s t r N r n s ( 1 ) = s t r N r n s ( 1 + 1)
s t r N m s ( 1 + 1 ) = tmpName
Madechange = T r u e
End I f
Next I
Wend
F o r I = L B o u n d ( s t r N m s 1 To U B o u n d ( s t r N m s )
Debug.Print I & " " & strNrns(1)
Next I
End Sub

Let's break down this procedure into segments.


I VBA String Functions I 89

D i m strNms(0 To 7 ) A s S t r i n g
strNms(0) = "Jerry"
strNms(1) = "Candice"
strNms(2) = "Brandon"
strNms(3) = "Kyle"
strNms(4) = "Benjamin"
strNms(5) = "Jacob"
strNms(6) = "Nathan"
strNms(7) = "Olivia"

The first thing we do is declare an array of strings and give each element
in the array a value.

D i m Madechange A s B o o l e a n
D i m tmpName A s S t r i n g
D i m I As L o n g
Madechange = T r u e

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.

W h i l e Madechange = T r u e
Madechange = F a l s e
F o r I = L B o u n d ( s t r N m s ) To U B o u n d ( s t r N m s ) - 1
I f StrComp(strNms(I), strNms(1 + 11,
vbBinaryCompare) = 1 Then
tmpName = s t r N m s ( 1 )
s t r N m s ( 1 ) = s t r N m s ( 1 + 1)
s t r N m s ( 1 + 1) = tmpName
Madechange = T r u e
End I f
Next I
Wend

The above section is the heart of the routine. We continue to look at


each value in the strNms array and compare it to the value in the array
just after it. If the value we are looking at is alphabetically greater than
the one after it, we swap the two elements in the array and set the
Madechange variable to True. Only after each value is examined and a
swap is not made do we continue with the next segment of our code.

F o r I = L B o u n d ( s t r N m s ) To U B o u n d ( s t r N m s )
Debug.Print I & " " & strNms(1)
Next I

The last little segment of code prints out the elements in the strNms
variable array in their sorted condition.
90 I Chapter 7: Working With Text I
Come back to this procedure after we have spent a little more time
working with VBA and it will be easier to follow. Sorting text is
accomplished easily and quickly using a Bubble Sort with the StrComp
function.

Len
Function Len(Expression1

The Len function tells us how many characters are in a string.

Sub TextWork09(
D i m L e v e l N a m e As S t r i n g
L e v e l N a m e = I n p u t B o x ( " E n t e r new l e v e l name: " & ~

(Must b e 8 c h a r a c t e r s ) " )
I f L e n ( L e v e l N a m e 1 <> 8 T h e n
MsgBox " T h e l e v e l name m u s t b e 8 c h a r a c t e r s . T r y a g a i n . "
End I f
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.

F u n c t i o n L e f t ( S t r i n g , L e n g t h As L o n g )
The Left function 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 T e x t w o r k l o (
D i m F i l e P a t h As S t r i n g
D i m F i l e D r i v e As S t r i n g
F i l e P a t h = A p p l ic a t i o n . A c t i v e D e s i g n F i 1 e . P a t h
F i l e D r i v e = L e f t ( F i 1 e P a t h . 1)
MsgBox " T h e c u r r e n t f i l e i s o n t h e " & F i l e D r i v e & " 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 FileDrive variable. A
MessageBox then displays the FileDrive variable with some other text.

Right
F u n c t i o n R i g h t ( S t r i n g , L e n g t h As L o n g )
I VBA String Functions I 91

You guessed it. The R i gh t function is a companion to the L e f t function.


It gives us the number of characters we ask for beginning with the last
(right) character.

Sub T e x t W o r k l l O
D i m FileName As S t r i n g
F i 1 eName = D i r ( " C : \ P r o g r a m F i 1 e s \ B e n t l e y \ M i c r o S t a t i o n \ * . * " , vbArchive)
W h i l e F i l e N a m e <> " "
MsgBox F i l e N a m e & " i s a " & R i g h t ( F i l e N a m e , 3 ) & " f i l e . "
FileName = D i r
Wend
End Sub

This procedure displays all of the files in the C:\frogrurn


Files\Bentley\MicroStution folder and their file extensions in message
boxes. Since there are quite a few, it will take a long time to click the OK
button on each message box.
HINT: When a program is executing, we can break into the execution of
the code by holding down the Control key (<CTRL>)and press the
<Break> key The break key is normally in the upper right-hand corner
of the keyboard.

F u n c t i o n M i d ( S t r i n g , S t a r t As Long, [ L e n g t h ] )
The M i d 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
specifying how many characters we want to have returned or we can
leave the Length parameter empty and have Mid return all of the
characters following the specified 'Start' character index.

Sub TextWorkl2()
D i m B o o k T i t l e As S t r i n g
B o o k T i t l e = " L e a r n i n g M i c r o S t a t i o n VBA"
D e b u g . P r i n t M i d ( B o o k T i t l e , 3 , 6)
D e b u g . P r i n t M i d ( B o o k T i t l e , 6)
Debug.Print Mid(BookTitle, InStr(1, BookTitle, " ") + 1)
End Sub
92 I Chapter 7: Working With Text I
We used the M i d function three times in
the above example, each time a little
arning
i n g M i c r o s t a t i o n VBA differently. The first time we asked M i d
M i c r o s t a t i o n VBA
to begin at the third character and to
return six characters in all. The second
time we asked for the sixth character
and each character after it. Notice how
we leave out the Length parameter entirely. The third time we did not
hard-code the beginning character. We used the I nSt r function to look
for the first space in the variable BookTitle and added one (1) to the
character number so we began with the character after the first space.
The length is not provided so we get everything after the space.

RepIace
F u n c t i o n R e p l a c e ( E x p r e s s i 0 n As S t r i n g , F i n d As S t r i n g , -
R e p l a c e As S t r i n g , -
[ S t a r t A s Long = 11, [ C o u n t A s Long = -11, -
[ C o m p a r e A s VbCompareMethod = v b B i n a r y C o m p a r e 1 ) As S t r i n g
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 T e x t W o r k l 3 0
D i m F i l e P a t h As S t r i n g
D i m F i l e p a t h 2 As S t r i n g
F i l e P a t h = A p p l i c a t i o n . A c t i v e D e s i g n F i l e . F u l l Name
Filepath2 = Replace(FilePath, \ , //I)
MsgBox F i l e P a t h & v b C r & t u r n s i n t o & v b C r & F i l e p a t h 2
End Sub

In this example we look for a backslash


then replace each one found with two
forward slashes.

InStr
Function InStr(CStart1, -
[ S t r i n g l l , CString21, -
[ C o m p a r e As VbCompareMethod = vbBinaryCompare1)
I n St r helps us identify where a character or group of characters appear
in a string. For example, if we look in the string ABCD for string C,
InStr returns the number 3 because C is the third character in
I VBA String Functions I 93

"ABCD': If the character(s) we are looking for is not found, I nS tr returns


a value of zero (0).

Sub TextWorkl4()
D i m F u l l N a m e As S t r i n g
D i m F i r s t s p a c e As Long
D i m F i r s t N a m e As S t r i n g
FullName = I n p u t B o x ( " E n t e r y o u r f u l l name.")
F i r s t s p a c e = I n S t r ( 1 , FullName, " " )
F i r s t N a m e = L e f t ( F u l l N a m e , F i r s t s p a c e - 1)
MsgBox " Y o u r f i r s t name i s " & F i r s t N a m e & " . "
End Sub

Here is another simple example of the use of the I n St r function. We ask


the user to enter hidher full name. We look for the first space in the
entered name, then get everything beginning from the start of the
FullName up to the character before the Firstspace.

Sub TextWorklS()
D i m F i l e P a t h As S t r i n g
D i m F i r s t F o l d e r P a t h As S t r i n g
D i m S e c o n d B a c k S l a s h As Long
F i 1 e P a t h = A c t i v e D e s i g n F i l e . F u l l Name
SecondBackSlash = I n S t r ( 4 , F i l e P a t h , " \ " )
F i r s t F o l d e r P a t h = L e f t ( F i l e P a t h , SecondBackSl a s h )
MsgBox F i l e P a t h & v b C r & F i r s t F o l d e r P a t h
End Sub

Often when we use I nSt r we begin looking


at the first character. This is why the
number one (1) appears as the first
parameter. In this example, however, we
begin by looking at the fourth character.
This is because we know that the third
character of a file path will likely be a backslash. The goal with
TextWorkl5 is to get the path ofthe root folder of the active DGN file.
One more example:

Sub TextWorklG()
Dim T e x t E l e m As T e x t E l e m e n t
Dim MyMod As Model R e f e r e n c e
Set MyMod = Application.ActiveModelReference
Dim MyElems As E l e m e n t E n u m e r a t o r
Set MyElems = MyMod.GetSelectedElements
Dim MyElem As E l e m e n t
94 I Chapter 7: Working With Text I
W h i l e MyElems.MoveNext
S e t MyElem = M y E l e m s . C u r r e n t
S e l e c t Case MyElem.Type
Case m s d E l e m e n t T y p e T e x t
S e t T e x t E l e m = MyElem
I f I n S t r ( 1 , T e x t E l e m . T e x t , " [ B Y ] " ) > 0 Then
TextElem.Text = Replace(TextElem.Text, -
" [ BY I" , " J KW " 1

T e x t E l em. R e w r i t e
End I f
End S e l e c t
Wend
End Sub

In this example we look at each selected element in the active file. If we


find a text element selected, we use I n St r to see if a particular string is in
the text element. If it is, I n S t r returns a number greater than zero (0).
When we know the search string is inside the text element, we use the
Replace function to replace "[BY]" with "JKW".
This is one way to perform 'Search and Replace' operations on our files.
You could use this when you need to place the name of a contractor in
your file but the file is created before the contract is awarded. Simply use
a tag, such as [CONTRACTOR],then replace it later with the name of
the contractor.

InStr Rev
F u n c t i o n I n S t r R e v ( S t r i n g C h e c k As S t r i n g , -
S t r i n g M a t c h As S t r i n g , -
[ S t a r t A s Long = -11, -
[Compare A s VbCompareMethod = v b B i n a r y C o m p a r e 1 ) As Long
I n S t r Rev, as the name implies, looks at the end of a string first instead of
the beginning. This is the reverse of I n S t r which begins looking at the
beginning. Here is one way to use it:

Sub TextWorkl7( 1
D i m F i l e P a t h As S t r i n g
D i m F o l d e r N a m e As S t r i n g
FilePath = ActiveDesignFile. Path
F o l d e r N a m e = M i d ( F i l e P a t h , I n S t r R e v ( F i 1 e P a t h . " \ "+I 1)
MsgBox " T h e c u r r e n t f i l e i s i n t h e " & F o l d e r N a m e & ~

"folder."
End Sub
I VBA String Functions I 95

We get the path of the current file, then use the I n S t r Rev function inside
a Mi d function to get the location of the first backslash we find. Since we
don't want to display the folder name beginning with the backslash, we
add one (1) in our Mid function to get the characters following the
backslash.

Split and Join


F u n c t i o n S p l i t ( E x p r e s s i o n As S t r i n g , [ D e l i m i t e r ] , -
[ L i m i t As Long = -11, -
[Compare As VbCompareMethod = vbBinaryCompare1)
Function Join(SourceArray, [ D e l i m i t e r ] ) As S t r i n g
Spl i t is used to take a String and split it into a text array.
J o i n takes an array and joins it into a String. We specify a delimiter for
each call. Let's take a look at one way to use Spl i t and J o i n.

Sub TextWorkl8()
D i m F i l e P a t h As S t r i n g
D i m NewTextFilePath As S t r i n g
D i m x S p l i t As V a r i a n t
F i 1 e P a t h = A c t i v e D e s i g n F i l e . F u l l Name
x S p l i t = Spl i t (F i l e P a t h , " \ " )
x S p l it(UBound(xSp1 i t ) )= x S p l i t ( U B o u n d ( x S p 1 it ) 1 & " . e x t r a c t "
NewText F i 1 ePa t h = J o in ( x S p l it , " \ " )
Open N e w T e x t F i l e P a t h F o r O u t p u t A s #1
P r i n t 81, F i l e P a t h
C l o s e 81
End Sub

In this example we want to create a new ASCII text file with an


extension ".extract" in the same folder as our active design file. Spl i t the
path of the active design file into an array using the S p l i t function.
Specify the backslash as the delimiter. When you step through the code,
this is what we have after the string is Spl i t:

6d NewTextFilePath "" String


VariantMring(0 to 3)
XSPlit(0) "C:" String
XSPlit(1) "Microstation VBA" String
XSPlit(2) "docs" String
XSPlit(3) "chapter07.dgn" String

The variable FilePath contains the path to the active design file. The
variable xSplit is an array Spl i t from FilePath using the backslash (\) as
96 I Chapter 7: Working With Text I
the delimiter. Take the last element in the array (using the UBound
function) and add a new file extension of .extract to it.
Next, Join the array with the backslash (\) as the delimiter into the
variable NewText FilePath.
Lastly, create an ASCII Text file using the NewTextFilePath variable as
the file name. Inside this new file print the contents of the FilePath
variable.
Here is what the
file looks like
when it is opened c:\Microstation vBA\docs\chaptero7.dgn

in Notepad.

Asc and Chr


F u n c t i o n A s c ( S t r i n g As S t r i n g ) As I n t e g e r
F u n c t i o n Chr(CharCode As Long)
The characters on our computer keyboards have an ASCII number
associated with them. Upper case X has its own unique number
different from lower case a: Some characters not on our keyboards
have their own ASCII number. You get the ASCII number of a character
with the Asc function. If you know the ASCII number of a character, you
can use the C h r function to get the character.

Sub TextWorkl9( 1
D i m s t r c h a r a c t e r As S t r i n g
F o r I = 0 To 2 5 5
D e b u g . P r i n t I & vbTab & C h r ( 1 )
Next I
End Sub
I VBA String Functions I 97

This code takes each ASCII character from 0


to 255 and prints it to the Debug 169 0
(Immediate) window. Now, why would we 170 a

want to do this? Because some of the ASCII


characters that are not on your keyboard can
171
172
173
-
<<

-
174 8
come in handy. For example, character 175 -
number 169 is the copyright symbol. 176
177 f
Character number 174 is the registered
symbol. Character 176 is the degrees symbol.
Character 177 is the plus/minus symbol used
for geometric tolerances.
Now that you know that character 169 is the copyright symbol, you can
use it in a message box:

Sub TextworkPo()
D i m s t r C o p y r i g h t N o t i c e As S t r i n g
strCopyrightNotice = " L e a r n i n g M i c r o s t a t i o n VBA " & -

Chr(169) & "2005"


MsgBox S t r C o p y r i g h t N o t i c e
End S u b

The As c function does the opposite of the C h r


function. You provide a character and get
back the ASCII number - something you
might do when creating graphical user
interfaces (GUIs).

P r i v a t e S u b T e x t B o x l L K e y P r e s s ( B y V a 1 K e y A s c i i As
MSForms.Return1nteger)
S e l e c t Case K e y A s c i i
Case A s c ( " 0 " ) To A s c ( " 9 " )
Case E l s e
KeyAscii = 0
End S e l e c t
End S u b

The preceding code is the K e y p r e s s E v e n t of a TextBox. The K e y p r e s s


E v e n t gives the ASCII number of the character the user attempted to
type into the TextBox. In this example, if the KeyAscii property contains
a number 0 through 9, then do nothing. Otherwise give the KeyAscii
98 I Chapter 7: Working With Text I
property a value of zero (0). The net result is that only numbers 0 to 9
can be entered into the TextBox.

FormatCurrency
Function ForrnatCurrency(Expression, -
C N u r n D i g i t s A f t e r D e c i m a l As Long = -11, -
C I n c l u d e L e a d i n g D i g i t As V b T r i S t a t e = vbUseDefaul t l , -
C U s e P a r e n s F o r N e g a t i v e N u r n b e r s As V b T r i S t a t e = -
vbUseDefaul t l , -
CGroupDigi t s As V b T r i S t a t e = vbUseDefau1 t l ) As S t r i n g
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( 1
D i m M y S a l a r y As D o u b l e
D i m M y s a l a r y 2 As D o u b l e
MySalary = 123456.78
Mysalary2 = 0.1234
MsgBox FormatCurrency(MySa1ary. 2 , v b f a l s e , v b f a l s e , v b T r u e )
MsgBox FormatCurrency(MySalary, 0 , v b f a l s e , v b f a l s e , v b T r u e )
MsgBox FormatCurrency(MySalary2, 2 , v b f a l s e , v b f a l s e , v b T r u e )
MsgBox FormatCurrency(MySalary2, 2 , v b T r u e , v b f a l s e , v b T r u e )
End Sub

FormatNumber
F u n c t i o n ForrnatNumber(Expression, -
C N u r n D i g i t s A f t e r D e c i m a l As Long = -11, -
C I n c l u d e L e a d i n g D i g i t As V b T r i S t a t e = vbUseDefaul t l , -
C U s e P a r e n s F o r N e g a t i v e N u r n b e r s As V b T r i S t a t e =
vbUseDefaul t l , -
CGroupDigi t s As V b T r i S t a t e = vbUseDefau1 t l ) As S t r i n g
I VBA String Functions I 99

FormatNumber looks the same as F o r m a t C u r r e n c y . The main difference is


that F o r m a t c u r r e n c y places a currency character in front of the number,
whereas FormatNumber returns only a formatted number.

Sub T e x t W o r k 2 2 ( )
D i m M y S a l a r y As D o u b l e
D i m M y s a l a r y 2 As D o u b l e
MySal a r y = 123456.78
Mysalary2 = 0.1234
MsgBox F o r m a t N u m b e r ( M y S a l a r y , 2, v b f a l s e , v b f a l s e , v b T r u e )
MsgBox F o r m a t N u m b e r ( M y S a l a r y , 0 , v b f a l s e , v b f a l s e , v b T r u e )
MsgBox F o r m a t N u m b e r ( M y S a l a r y 2 , 2 , v b f a l s e , v b f a l s e , v b T r u e )
MsgBox F o r m a t N u m b e r ( M y S a l a r y 2 , 2 , v b T r u e , v b f a l s e , v b T r u e )
End Sub

FormatDateTime
F u n c t i o n FormatDateTime(Expression, -
CNamedFormat As VbDateTimeFormat = v b G e n e r a l D a t e 1 ) -
As S t r i n g
Use F o r m a t D a t e T i m e to specify a datehime and how format it. Here are
your options and the results:

Sub T e x t W o r k 2 3 ( )
D i m DateToFormat As Date
DateToFormat = "1/1/2005 4:45 PM"
MsgBox F o r m a t D a t e T i m e ( D a t e T o f o r m a t , vbGeneralDate)
MsgBox F o r m a t D a t e T i m e ( D a t e T o f o r m a t , v b L o n g D a t e )
MsgBox F o r m a t D a t e T i m e ( D a t e T o f o r m a t , v b L o n g T i m e )
MsgBox F o r m a t D a t e T i m e ( D a t e T o f o r m a t , v b S h o r t D a t e )
MsgBox F o r m a t D a t e T i m e ( D a t e T o f o r m a t , vbShortTime)
End Sub
100 I Chapter 7: Working With Text I

Format
Function Format(Expression, [Format], -
C F i r s t D a y O f W e e k A s VbDayOfWeek = v b S u n d a y 1 , -
C F i r s t W e e k O f Y e a r A s VbFi r s t W e e k O f Y e a r = v b F i r s t l l a n l l )

We already have examples of specific types of formatting:


Fo rmat C u r ren cy, Fo r ma t N umb e r, Fo rmat D a t eT ime. 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 T e x t W o r k 2 4 0
D i m MyPhone As S t r i n g
My P hone = "800 5 5 5 1212 "
MsgBox F o r m a t ( My Phone, " (IHHI) l ~ l ~ l ~ - l1~ l ~ l ~ l ~ "
End Sub

The Format parameter in the Format function


allows a great deal of flexibility. See the VBA
Help file for more formatting options.

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 <F8> button.
The next section deals with numbers.
Working With Numbers

For hundreds and even thousands of years, the worlds greatest


mathematicians attempted to calculate an accurate value for Pi. When
asked about this value today, we casually state 3.14159 or something
close to it. A2 + B2 = C2. This formula is second nature to children on
our schools playgrounds today, whereas not long ago the equality of the
sum of the squares of the sides of a right triangle to the square of the
hypotenuse was a great unknown.
While software development, in general, deals in large part with logic,
add Microstation to the mix and the need to manipulate numbers
increases exponentially. After all, what is a line? The shortest distance
between two points. Each of these points is composed of three numeric
values: an X, a Y, and a Z. To draw a circle at the midpoint of that line in
VBA, we need to calculate the lines midpoint. How do we do that? Find
the phone number of a math teacher? Not so, my friend.

NUMERIC
FUNCTIONS
VBA makes working with numbers a breeze. It doesnt do all of the work
for us, but we can do a great deal with very little pain.

103
I Chapter 8: Working With Numbers I

Addition
1 + 1 = 2. We learned this many, many years ago. The plus symbol (+) is
used in VBA to add numbers. Take a look:

Sub TestAdditionSubtractionO
D i m S e l P t As P o i n t 3 d
D i m C e n P t As P o i n t 3 d
D i m CadMsg As C a d I n p u t M e s s a g e
D i m T e x t E l e m As T e x t E l e m e n t
D i m R o t M a t r i x As M a t r i x 3 d
S e t CadMsg = Application.CadInputQueue.Get1nput
Do W h i l e T r u e
S e l e c t Case C a d M s g . I n p u t T y p e
Case msdCadInputTypeDataPoint
Sel P t = CadMsg. P o i n t
E x i t Do
End S e l e c t
Loop
CenPt = SelPt
CenPt.X = CenPt.X + 1
S e t TextElem = Appl i c a t i o n . C r e a t e T e x t E 1 e m e n t l ( N o t h i n g , "l", ~

CenPt, R o t M a t r i x )
ActiveModel Reference.AddElement TextElem
CenPt = SelPt
CenPt.Y = CenPt.Y + 1
S e t TextElem = Appl i c a t i o n . C r e a t e T e x t E 1 e m e n t l ( N o t h i n g , "Z", -
CenPt, R o t M a t r i x )
ActiveModel Reference.AddElement TextElem
CenPt = SelPt
CenPt.X = CenPt.X - 1
S e t TextElem = Appl i c a t i o n . C r e a t e T e x t E 1 e m e n t l ( N o t h i n g , "3", ~

CenPt, R o t M a t r i x )
ActiveModel Reference.AddElement TextElem
CenPt = SelPt
CenPt.Y = CenPt.Y - 1
S e t T e x t E l e m = Application.CreateTextElementl(Nothing, "4", ~

CenPt, R o t M a t r i x )
ActiveModel Reference.AddElement TextElem
End Sub
I Numeric Functions I 105

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 TestAdditionSubtraction.

Mu1tip1ication
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 TestMultiplicationO
Dim DistanceInInches A s Double
Dim DistanceInMM A s Double
DistanceInInches = CDbl (InputBox(Enter distance in inches:))
DistanceInMM = DistanceInInches * 25.4
106 I Chapter 8: Working With Numbers I
MsgBox D i s t a n c e I n I n c h e s & " i s equal t o " & -

DistanceInMM & " Millimeters."


End Sub

Multiplying the entered value by 25.4 converts the entered value from
inches to millimeters.

Division
There are two ways to divide numbers in VBA. No, not long division
and short division. The first method returns a very precise number.
When you want precision (and you usually do), use the forward slash ( /
) symbol like this: 5 / 2 = 2.5

F u n c t i o n T o M i l e s ( D i s t a n c e 1 n F e e t as D o u b l e ) A s D o u b l e
T o M i l e s = D i s t a n c e I n F e e t / 5280
End F u n c t i o n

The function ToMi 1 es 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.

Squares and Exponents


Remember A2 + B2 = C2? The little twos shown above the A, B, and C
square the values of A, B, and C.
In VBA, we write the expression like this:
A^2 + B^2 = C"2. The caret symbol allows an exponent. If you were to
cube (raise to the power of 3) a number, you would use DA3.

Function GetCircleArea(Circ1eRadius A s D o u b l e ) As D o u b l e
D i m P i As D o u b l e
Pi = Atn(1) * 4
GetCircleArea = Pi * CircleRadius 2
End F u n c t i o n
I Numeric Functions I 107

Square Root
Use the Sqr function to get the square root of a number. Here's one way
to use it:

Sub G e t L i n e L e n g t h O
D i m SelElem As Element
D i m LineElem As LineElement
D i m S e l Elems As E l e m e n t E n u m e r a t o r
S e t S e l Elems = ActiveModelReference.GetSelectedElements
W h i l e SelElems.MoveNext
Set SelElem = SelElems.Current
S e l e c t Case S e l E l e m . T y p e
Case m s d E l e m e n t T y p e L i n e
S e t L i n e E l em = S e l E l em
D i m S t P t As P o i n t 3 d
D i m EnPt As P o i n t 3 d
StPt = LineElem.StartPoint
EnPt = LineElem.EndPoint
LineLength = Sqr((StPt.X - EnPt.X) A 2 + ~

(StPt.Y - EnPt.Y) 2)
MsgBox " L i n e f o u n d w i t h l e n g t h o f " & LineLength
End S e l e c t
Wend
End Sub

Pythagorean's theorem is used in this example. We get the change in X


and the change in Y of the selected line. We square these values, add
them together, then get the square root of the total.

Sine, Cosine, Tangent


The S i n , Cos, and Tan functions require an angle in radians.

Sub T e s t S i n C o s O
D i m XChange A s D o u b l e
D i m YChange As D o u b l e
D i m P i As D o u b l e
D i m H y p L e n g t h As D o u b l e
D i m HypAngleDegrees As Double
D i m HypAngleRadians As Double
Pi = Atn(1) * 4
108 I Chapter 8: Working With Numbers I
HypLength = C D b l ( I n p u t B o x ( " E n t e r Hypotenuse L e n g t h : " ) )
HypAngleDegrees = CDbl ( I n p u t B o x ( " E n t e r A n g l e : " ) )
HypAngleRadians = HypAngleDegrees * P i / 180
YChange = HypLength * Sin(HypAng1eRadians)
XChange = HypLength * Cos(HypAng1eRadians)
Debug. P r in t " T e s t S i n Cos ( 1 "
Debug.Print "HypLength = " & HypLength
Debug.Print "HypAngleDegrees = " & HypAngleDegrees
Debug.Print "HypAngleRadians = " & HypAngleRadians
D e b u g . P r i n t "XChange = " & XChange
D e b u g . P r i n t "YChange = " & YChange
End Sub

To calculate the change in X and the change in Y,we need hypotenuse


length and an angle, as long as we have access to the Sin and Cosine of
the angle. After getting the user input, convert the supplied angle in
degrees to radians. Then use the angle in radians with the S i n and Cos
functions to give change in X and change in Y

TestSinCos ( )
HypLength = 1 0
HypAngleDegrees = 3 0
HypAngleRadians = 0 , 5 2 3 5 9 8 7 7 5 5 9 8 2 9 9
XChange = 8 . 6 6 0 2 5 4 0 3 7 8 4 4 3 9
YChange = 5

Let's use the T a n function now. The first example supposes you know the
leg of the triangle along the X axis.

Sub TestTanl( 1
D i m XChange As D o u b l e
D i m YChange As D o u b l e
D i m P i As D o u b l e
D i m H y p A n g l e D e g r e e s As D o u b l e
D i m H y p A n g l e R a d i a n s As D o u b l e
Pi = Atn(1) * 4
XChange = CDbl(InputBox("Enter X Side Length:"))
HypAngleDegrees = CDbl ( I n p u t B o x ( " E n t e r A n g l e : " ) )
HypAngleRadians = HypAngleDegrees * P i / 180
YChange = Tan(HypAng1eRadians) * XChange
Debug.Print "TestTanl( 1"
I Numeric Functions I 109

Debug.Print "XChange = " & XChange


Debug. P r i n t " H y p A n g l e D e g r e e s = " & HypAngl eDegrees
Debug.Print "HypAngleRadians = " & HypAngleRadians
Debug.Print "YChange = " & YChange
End Sub

TestTanlO
XChange = 4
HypAngleDegrees = 36.8699
HypAngleRadians = 0.643501149881057
YChange = 3.00000025679859

Sub T e s t T a n 2 ( )
D i m XChange As D o u b l e
D i m YChange As D o u b l e
D i m P i As D o u b l e
D i m H y p A n g l e D e g r e e s As D o u b l e
D i m H y p A n g l e R a d i a n s As D o u b l e
Pi = Atn(1) * 4
YChange = CDbl(InputBox("Enter Y Side Length:"))
HypAngleDegrees = CDbl ( I n p u t B o x ( " E n t e r A n g l e : " ) )
HypAngleRadians = HypAngleDegrees * P i / 180
XChange = YChange / T a n ( H y p A n g 1 e R a d i a n s )
Debug. P r i n t " T e s t T a n Z ( ) "
Debug.Print "YChange = " & YChange
Debug. P r i n t " H y p A n g l e D e g r e e s = " & HypAngleDegrees
Debug. P r i n t " H y p A n g l e R a d i a n s = " & HypAngleRadians
Debug.Print "XChange = " & XChange
End Sub

TestTan2 ( )
YChange = 3
HypAngleDegrees = 36.8699
HypAngleRadians = 0.643501149881057
XChange = 3.99999965760191
110 I Chapter 8: Working With Numbers I

The values used


for the previous
examples make
use of the right
triangle:

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 doesnt work. It is
helpful to test our calculations with numbers that give us predictable
results.

Arc Tangent
S i n, Cos, and Tan help when we know the angle involved. If we do not
know the angle, we can get the angle by using A t n (ArcTangent).

Sub TestATan( 1 ________________


D i m P i As D o u b l e
D i m A n g l e D e g r e e s As D o u b l e
D i m A n g l e R a d i a n s As D o u b l e
Pi = Atn(1) * 4
AngleRadians = Atn(3 / 4)
AngleDegrees = AngleRadians / P i * 180
MsgBox A n g l e D e g r e e s
End Sub

Absolute Value
The Abs function gives us the Absolute Value of the supplied number.

Sub TestAbs()
D e b u g . P r i n t The a b s o l u t e v a l u e o f 4 i s & Abs(4)
D e b u g . P r i n t The a b s o l u t e v a l u e o f - 5 i s & Abs(-5)
End Sub
I Numeric Functions I 111

The a b s o l u t e v a l u e o f 4 is 4
The a b s o l u t e v a l u e o f -5 is 5

Convert to Integer, to Long, to Double, and Value


We have discussed declaring types of variables. VBA gives us the ability
to convert values from one type to another.
One of the most common conversions is from a string to a number.

YChange = CDbl(InputBox(Enter Y Side Length:))

Above we use the CDbl function to convert the results of the InputBox to
a double.

Sub TestCInt()
Debug.Print CInt(4.56)
Debug.Print CInt(4.23)
Debug.Print C I n t C 4 . 5 6 )
Debug.Print C I n t C 4 . 2 3 )
End Sub

When converting from a double to an integer,


something needs to be done with the decimal
5 portion of the number because an integer is a
4 whole number. It is important that you
-5
-4 understand how this works. C In t arrives at an
integer by rounding the number. Take a look
at the code in TestCInt and the results
shown in the Immediate window.

CLng
The C Ln g function works just like the C In t function, except it converts
the provided number to a long. You could ask, If CLng does the same
thing as CInt, which one should I use? That is a good question.
Remember, that a long number can be significantly larger than an
integer. To use C I n t on a number such as 40,000.123 would create an
overflow error. C I n t and C Ln g are often used when assigning a value to a
112 I Chapter 8: Working With Numbers I
variable. So, if you assign a value to a variable declared as an integer, you
should use CInt. If you are assigning a value to a variable declared as a
long, use CLng.

Sub T e s t C L n g ( 1
D e b u g . P r i n t CLng(40000.56)
40001
D e b u g . P r i n t CLng(40000.23) 40000
Debug.Print CLng(-40000.56) -40001
-40000
Debug.Print CLng(-40000.23)
End Sub

The F i x function looks like it works the same as the CInt 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 T e s t F i x ( )
Debug. P r i n t F i x ( 4 0 0 0 0 . 5 6 )
Debug.Print Fix(40000.23)
Debug.Print Fix(-40000.56)
Debug.Print Fix(-40000.23)
End Sub

The F i x function simply drops the decimal


portion of the provided number. It does not
40000
40000
do any rounding. Fix can return numbers
-40000 that fall within the integer and long range.
-40000

C Db 1 converts the supplied parameter to a double.

Sub T e s t D o u b l e ( 1
D i m L i n e L e n g t h As D o u b l e
LineLength = CDbl ( I n p u t B o x ( " E n t e r t h e l i n e l e n g t h : " ) )
End Sub
I Numeric Functions I 113

CInt, CLng, and CDbl 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 Val
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 TestVal ( 1
Debug. P r i n t V a l ( " 4 . 5 " " " )
Debug.Print Val("4.5 inches")
Debug.Print Val ( " $ 5 , 0 0 0 " )
Debug.Print Val ( " 4 5 d e g r e e s " )
D e b u g . P r i n t V a l ( " A p p r o x . 5280 f e e t " )
Debug.Print Val("23 f e e t 12 inches")
End Sub

Notice that when the parameter supplied to


the Val function begins with a numeric
value, Val returns all of the numeric
characters until it finds a non-numeric
character and returns the numeric values it
found.
rn

IsNumeric
Many of the functions we have just reviewed return numeric values.
I s N u m e r i c returns a Boolean value (True or False). It looks at the
parameter and determines if it is numeric.

Sub TestIsNumeric( 1
Debug. P r in t I s Nume r ic ( " 4 . 5 " " " )
Debug. P r in t I s Nume r ic ( " 4 . 5 in c h e s " )
Debug. P r i n t I s N u m e r i ~ ( " $ 5 , 0 0 0 " )
Debug . P r in t Is N ume r ic ( " 4 5 d e g r e e s " )
Debug.Print IsNumeric("Approx. 5280 f e e t " )
Debug.Print IsNumeric("23 f e e t 12 inches")
End Sub
114 I Chapter 8: Working With Numbers I
IsNurneric looks at the entire parameter
and determines if it is numeric. If any
portion of the parameter is not numeric,
we get a false value returned. Notice how
the dollar sign ($) is a numeric sign.

Round
C I n t and C Lng 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 TestRound()
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(l.4, 0)
Debug.Print Round(l.5, 0) L

End S u b

Mod - Find the Remainder


The Mod function gives the remainder value of two numbers, but you use
it quite differently than most other functions. Where most functions call
the function then provide parameters separated by commas,. in the Mod
function you supply the numerator, call Mod, then supply the
denominator.

Sub TestModl( 1
Debug.Print 5 Mod 2
Debug.Print 7 Mod 3
Debug.Print 23 Mod 7
Debug.Print 280 Mod 2
End S u b
I Numeric Functions I 115

Sgn - Show me a sign


Is a number positive or negative? Or is it neither? The Sgn function
returns a value of - 1,0, or 1 depending on whether the supplied value is
negative, zero, or positive.

Sub TestSgn( 1
Debug.Print SgnC4.5)
Debug.Print Sgn(0)
Debug.Print Sgn(4.5)
End Sub

Rnd and Randomize


Once in a while you need to generate a random number. This example
shows how to create a random number between a lower and higher
number. The result is a random point cloud consisting of 300 points
between (25,25) and (50,50).

Sub TestRnd( 1
D i m I As L o n g
D i m Lower As Long
D i m H i g h e r As Long
D i m P o i n t C e n ( 0 To 1) As P o i n t 3 d
D i m P o i n t E l e m As P o i n t S t r i n g E l e m e n t
Lower = 25
Higher = 50
Randomize
For I = 1 To 3 0 0
PointCen(O).X = Round((Higher - Lower + 1) * R n d ( l ) , 2)
PointCen(O).Y = Round((Higher - Lower + 1) * R n d ( l ) , 2)
PointCen(l).X = PointCen(O).X
PointCen(l).Y = PointCen(O).Y
Set PointElem = ~

Application.CreatePointStringElementl(Nothing, ~

PointCen, True)
ActiveModelReference.AddElement PointElem
Next I
End Sub
116 I Chapter 8: Working With Numbers I

Order of Operations
2 + 5 * 8 / 1 2 + 13 = ?
(2 + 5) * 8 / (12 + 13) = ?
2 + (5 * 8 / (12 + 13)) = ?
Each of these expressions returns a different result. The numbers are the
same and the operations are the same but the 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
should calculate your expressions.

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.
Standard VBA Calls

While introducing various concepts, we used a number of standard


VBA calls without discussing them, so let's cover them now. Again, you
can use these VBA calls with other VBA-enabled applications such as
Microsoft Excel.

MESSAGE
BOXES
We used MessageBoxes to display some text with an OK button. By
default, the code pauses until the user clicks the OK button.

Sub T e s t M e s s a g e B o x l O
MsgBox "Your h a r d d r i v e w i l l now b e f o r m a t t e d . "
End Sub

This is just what we all want to see: A


MessageBox informing us something
drastic is about to happen and all we have is
an OK button to click on.
You can specify the prompt of the
MessageBox (the text that shows up) as well
as which buttons display.

117
118 I Chapter 9: Standard VBA Calls I
Sub T e s t M e s s a g e B o x 2 0
D i m MsgResp As VbMsgBoxResul t
MsgResp = MsgBox("Unab1e t o open f i l e . " , VbAbortRetryIgnore)
MsgResp = MsgBox("Format H a r d D r i v e ? " , vbOKCancel )
MsgResp = MsgBox("New L e v e l A d d e d . " , vbOK0nly)
MsgResp = MsgBox("Not Connected t o I n t e r n e t . " , vbRetryCance1)
MsgResp = MsgBox("Do y o u want t o c o n t i n u e ? " , vbYesNo)
MsgResp = M s g B o x ( " C o n t i n u e Reading F i l e ? " , vbYesNoCance1 )
S e l e c t Case MsgResp
Case VbMsgBoxResult.vbAbort
' P l a c e Code Here
Case VbMsgBoxResul t.vbCance1
' P l a c e Code Here
Case V b M s g B o x R e s u l t . v b I g n o r e
' P l a c e Code Here
Case VbMsgBoxResul t . v b N o
' P l a c e Code Here
Case VbMsgBoxResul t.vbOK
' P l a c e Code Here
Case VbMsgBoxResul t . v b R e t r y
' P l a c e Code Here
Case VbMsgBoxResul t . v b Y e s
' P l a c e Code Here
End S e l e c t
End Sub

The ability to have more than an OK button makes the MessageBox


much more powerful. Now, however, you are asking a question of the
user. Yes? No? Retry? Abort? Ignore? Cancel? OK? When you ask a
question, you need an answer. So, we use the MessageBox as a function
and get its return value.
I MessageBoxesI 119

In the example above, which is only for illustration purposes, each


MessageBox returns a value into the variable MsgResp that tell us which
button the user clicked. We use a Select Case statement to determine the
button pressed, then execute code based on the button. The Select Case
Statement is placed after the "YesNoCancel" MessageBox so previous
button clicks are not considered, only the "YesNoCancel" MessageBox.

Here is a Microsoft Windows MessageBox that appears when you


attempt to change a file's extension (say from .txt to .dgn). Note the Yes
and No buttons. We now know how to specify buttons but what about
the exclamation point in the triangle? How do we do that?
When you display a MessageBox, use constants that specify which
buttons to display, such as vbOKCancel, vbYesNo, and vbOKOnly.
These constants have numeric values. There are other constants that
specify which icon to display, such as vbExclamation. When you add the
constant specifying the buttons to display with the constant for the icon
to display, VBA displays the buttons and the icon in the MessageBox.

Sub T e s t M e s s a g e B o x 3 0
D i m MsgResp A s V b M s g B o x R e s u l t
MsgResp = M s g B o x ( " U n a b 1 e t o open f i l e . " , -
vbAbortRetryIgnore + v b c r i t i c a l )
MsgResp = M s g B o x ( " F o r m a t H a r d D r i v e ? " , -
vbOKCancel + v b E x c l a m a t i o n )
MsgResp = MsgBox("New L e v e l A d d e d . " , vbOKOnly + vbInformation)
MsgResp = MsgBox("Do y o u w a n t t o c o n t i n u e ? " , vbYesNo + -
vbQuestion)
End Sub
120 I Chapter 9: Standard VBA Calls I

When using these icon constants with button constants, Windows


displays the buttons and the icon and plays specific sounds.
Let's look at another available parameter when using the MessageBox.

Sub TestMessageBox40
MsgBox " T e s t i n g T i t l e " , v b c r i t i c a l , " T i t l e Goes H e r e "
MsgBox " T e s t i n g T i t l e " , , " T i t l e Goes H e r e "
End Sub

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 I nputBox returns an empty
string. An empty string is denoted in VBA as two quotation symbols
with no other character between them ("").
I InputBox I 121

S u b TestInputBoxl( 1
Dim InpRet As String
I n p R e t = I n p u t B o x ( " E n t e r Level Name:")
Debug.Print "User entered " & InpRet
End S u b

The I nputBox has additional parameters we can use. We will discuss four
of them here.

S u b TestInputBoxP( 1
Dim InpRet As String
I n p R e t = I n p u t B o x ( " E n t e r Level Name:", -
"Level C r e a t o r " , " S t r i p i n g " , 0, 0)
Debug.Print "User entered " & InpRet
End S u b

OK

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,O
as your coordinates, the InputBox displays in the upper-left corner of
the monitor independent of where the Microstation window is placed.
Be careful with the X and Y location parameters because it is possible to
place the InputBox entirely off screen. It would surely confuse the user if
he could not see the InputBox and the code is waiting for a click on a
button or the <Enter>key.
122 I Chapter 9: Standard VBA Calls I

Now!
The Now function gives the current system date and time. This is useful
to make a datehime stamp. Now returns a Date type value.

Sub T e s t N o w ( )
MsgBox Now
End Sub

DateAdd
Now tells us the current datehime. DateAdd allows us to look into the
future or into the past. Here are a few examples of how to use DateAdd:

Sub T e s t D a t e A d d ( )
D i m NowDate As D a t e
NowDate = Now
D e b u g . P r i n t NowDate & v b T a b & D a t e A d d ( " d " , 4 , NowDate) ' D a y
D e b u g . P r i n t NowDate & v b T a b & D a t e A d d ( " h " , 4 , NowDate) ' H o u r
D e b u g . P r i n t NowDate & v b T a b & D a t e A d d ( " n " , 4 , NowDate) ' M i n u t e
D e b u g . P r i n t NowDate & v b T a b & D a t e A d d ( " s " , 4 , NowDate) ' S e c o n d
D e b u g . P r i n t NowDate & v b T a b & D a t e A d d ( " m " , 4 , NowDate) ' M o n t h
D e b u g . P r i n t NowDate & v b T a b & D a t e A d d ( " w " , 4 , NowDate) 'Week
D e b u g . P r i n t NowDate & v b T a b & D a t e A d d ( " y y y y " , 4 , N o w D a t e ) ' Y e a r
D e b u g . P r i n t NowDate & v b T a b & D a t e A d d ( " q " , 1, N 0 w D a t e ) ' Q u a r t e r
End Sub

5/28/2005 11:40:54 AM 6/1/2005 11:40:54 AM


5/28/2005 11:40:54 AM 5/28/2005 3:40:54 PM
5/28/2005 11:40:54 AM 5/28/2005 11:44:54 AM
5/28/2005 11:40:54 AM 5/28/2005 11:40:58 AM
5/28/2005 11:40:54 AM 9/28/2005 11:40:54 AM
5/28/2005 11:40:54 AM 6/1/2005 11:40:54 AM
5/28/2005 11:40:54 AM 5/28/2009 11:40:54 AM
5/28/2005 11:40:54 AM 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 datehime. Use a positive
I InputBox 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.

If you have two dates and want to know the time interval between them,
use DateDiff. Use the same interval parameters with DateAdd and
DateDi ff.

Sub TestDateDi f f ( )
D i m NowDate A s D a t e
NowDate = Now
D e b u g . P r i n t " D a y s " & vbTab & D a t e D i f f ( " d " , NowDate, " 1 / 1 / 3 0 0 0 " )
D e b u g . P r i n t " H o u r s " & vbTab & D a t e D i f f ( " h " , NowDate, " 1 / 1 / 3 0 0 0 " )
Debug. P r i n t " M i n u t e s " & vbTa b & D a t e D i f f ( " n " , NowDa t e , "1/ 1/3000" )
Debug. P r i n t "Seconds " & vbTa b & D a t e D i f f ( " s " , NowDa t e , "1/ 1/3000" )
Debug. P r i n t " M o n t h s " & v bTa b & Da t e D i f f ( " m " , Now D a t e , " 1/ 1 / 3 0 0 0 " )
D e b u g . P r i n t "Weeks" & vbTab & D a t e D i f f ( " w " , NowDate, " 1 / 1 / 3 0 0 0 " )
Debug. Pr in t " Y e a r s " & vbTa b & D a t e D i f f ( " y y y y " , NowDa t e , " 1/ 1 / 3 0 0 0 " )
Debug. Pr in t " Q u a r t e r s " & vbTa b & D a t e D i f f ( " q " , NowDa t e , " 1/ 1 / 3 0 0 0 " )
End S u b

The Y2K scare was nothing more


than a scare for most of us. This
Days 363269
example looks forward to Y3K. Hours 8718445
How many days, hours, minutes, Minutes 523106644
Seconds 3 13 8 63 9 8 632
seconds, months, weeks, years, Months 11936
and quarters before the dreaded Weeks 51895
Years 995
January lst, 3000 comes our way? Quarters 3979
Only 31,386,398,632 seconds.
The interval is the first parameter.
The next two parameters are the dates we are looking at. If the first date
comes before the second date, we get a positive return value. If the first
date comes after the second date, we are returned a negative value.
124 I Chapter 9: Standard VBA Calls I

Timer
The T i me 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.

Sub T e s t T i m e r ( )
MsgBox T i m e r
End Sub

FileDateTime
FileDateTime gives the datehime the specified file was last modified.

Sub T e s t F i 1 e D a t e T i m e ( 1
D i m e x e D a t e As D a t e
exeDate = FileDateTime -
( " C : \ P r o g r a m F i 1 e s \ B e n t l e y \ M i c r o s t a t i o n \ u s t a t i on . e x e " )
MsgBox " M i c r o S t a t i o n D a t e / T i m e : " & exeDate
End Sub

F i 1 elen tells the size (in bytes) of a given file.

Sub T e s t F i 1e L e n ( )
D i m e x e S i z e As L o n g
exeSize = FileLen
( " C : \ P r o g r a m F i 1 e s \ B e n t l e y \ M i c r o s t a t i o n \ u s t a t i on . e x e " )
MsgBox " M i c r o S t a t i o n S i z e : " & exesize
End Sub

ruse M k D 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 InputBox I 125

named c:\MicroStation VBA\Chapters\09\Samples but the Chapters


directory does not exist, you must create the Chapters directory, then
the 09 directory, then the Samples directory.

Sub TestMkDi r ( 1
MkDi r c : \ M i c r o s t a t i o n V B A \ S o u r c e C o d e
End Sub

RmDir
RmDi r removes a directory from the file system. The directory must be
empty, otherwise an error occurs.

Sub TestRmDi r(1


R m D i r c :\ M i c r o s t a t i o n VBA\Source Code
End Sub

Dir
The D i 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). D i r only returns one file/folder at a time. If you are looking
for a group of files or folders, call D i r again and leave the parameters
empty. When D i 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 pathhame to look for, you can specify the type of file/folder.
Since there is a great deal that you can do with the D i r function, we will
look at several examples and the results of the code.

Sub T e s t D i r l ( )
D i m R o o t P a t h As S t r i n g
D i m D i r R e t u r n As S t r i n g
RootPath = C:\Program Files\Bentley
DirReturn = Dir(RootPath & \*.*, vbDirectory)
Whi 1 e D i r R e t u r n <>

Debug.Print RootPath & \ & D i r R e t u r n


DirReturn = Dir
Wend
End Sub
126 I Chapter 9: Standard VBA Calls I

Our first example retrieves Directories under the "C:\frogrurn


Files\Bentley" directory. Notice how the first directory is named "I' and
the second, "..? This occurs with all calls when looking for directories
and they should be ignored in your code. They refer to the current
folder and the parent folder.

Sub T e s t D i r2( I
D i m R o o t P a t h As S t r i n g
D i m D i r R e t u r n As S t r i n g
RootPath = "C:\Program Files\Bentley\MicroStation"
DirReturn = Dir(RootPath & "\*.*"I
While DirReturn <> "I'

Debug.Print RootPath & " \ " & D i r R e t u r n


DirReturn = Dir
Wend
End Sub

Now we are looking in the "C:\frogrurn Files\Bentley\MicroStution"


folder for all files (*.*).
Writing file names to the Immediate window works well for
demonstration but is not practical. Let's do another variation this time
putting the file names into a variable.

Sub T e s t D i r3( I
D i m R o o t P a t h As S t r i n g
D i m D i r R e t u r n As S t r i n g
I InputBox I 127

D i m D g n F i l e s O As S t r i n g
ReDim D g n F i l e s ( 0 ) A s S t r i n g
Root Path = " C : \ M i c r o St a t ion V B A\ Docs "
DirReturn = Dir(RootPath & "\*.dgn")
Whi 1 e D i r R e t u r n <> " "

DgnFiles(UBound(DgnFi1es)) = RootPath & " \ " & D i r R e t u r n


ReDim P r e s e r v e D g n F i l e s ( U B o u n d ( D g n F i 1 e s ) + 1)
DirReturn = Dir
Wend
ReDim P r e s e r v e D g n F i l e s ( U B o u n d ( D g n F i 1 e s ) - 1)
End S u b

DgnFiles(0) "C:
WlicroStation VBAIDocskhapter03.dgn"
DgnFiles(1) "C:
WlicroStation VBAIDocskhapter04.dgn"
DgnFiles(2) "C:
WlicroStation VBAIDocskhapterO6.dgn"
DgnFiles(3) "C:
WlicroStation VBAIDocskhapter07.dgn"
DgnFiles(4) "C:
WlicroStation VBAIDocskhapter08.dgn"
DgnFiles(5) "C:
WlicroStation VBAIDocskhapterO9.dgn"

We look in the directory "C:\MicroStution VBA\Docs" 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".

WARNING: The K i 1 1 function ispermanent. Files that are 'Killed'are


not sent to the recycle bin. They are destroyed totally and completely.
Use with extreme caution.

S u b T e s t K i 11 ( )
K i l l "C:\MicroStation VBA\Docs\killtest.txt"
End S u b

This code kills a file named C:\MicroStution VBA\Docs\killtest. txt.


The ability to delete a file is useful and necessary but must be used with
caution.
128 I Chapter 9: Standard VBA Calls I

Beep beeps. It offers a quick, audible clue to the user as our code
executes. Although useful to draw the user's attention to the program, it
can become annoying to have an application beep every time a user does
something.

Sub TestBeep(
Beep
End Sub

Savesetting
Working with the Windows registry can save settings the user has set in
our software. Microsoft has created a registry path for VBA program
settings that we can easily write to, edit, and delete.

Sub T e s t s a v e s e t t i n g ( )
S a v e s e t t i n g " L e a r n i n g M i c r o s t a t i o n VBA", "Chapter 9",-
" S a v e s e t t i n g " , "It Works"
End Sub

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 Se t t in g.

Sub T e s t G e t S e t t i n g (
D i m R e g S e t t i n g As S t r i n g
Regsetting = G e t S e t t i n g ( " L e a r n i n g M i c r o s t a t i o n VBA". "Chapter 9 " . ~

"Savesetting")
D e b u g . P r i n t "The Key S a v e s e t t i n g v a l u e i s " " " & RegSetting & " " " "

End Sub
I InputBox I 129

The Key Savesetting value i s "It Works"

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.

S u b TestDeleteSettingl()
D e l e t e s e t t i n g " L e a r n i n g M i c r o s t a t i o n VBA",
"Chapter 9", " S a v e s e t t i n g "
End S u b

When the above code is run, the Key "Savesetting is deleted.

S u b TestDeleteSetting2()
D e l e t e s e t t i n g " L e a r n i n g M i c r o s t a t i o n VBA", "Chapter 9"
End S u b

TestDel eteSetti n g 2 deletes the Registry Section "Chapter 9':

S u b TestDeleteSetting3()
D e l e t e s e t t i n g " L e a r n i n g M i c r o s t a t i o n VBA"
End S u b

TestDel eteSetti ng3 deletes the entire "Learning Microstation VBA"


Application Name from the Registry and all of its sub-entries.

GetAllSettings
GetAl 1 Settings, as the name implies, gets all keys under the specified
app name and section and places them into a multi-dimensional array.

S u b TestGetSettings( 1
D i m A l l s e t t i n g s As V a r i a n t
A l l s e t t i n g s = GetAllSettings("Learning M i c r o s t a t i o n V B A " , -
" C h a p t e r 9")
End S u b
130 I Chapter 9: Standard VBA Calls I

AIISettings(0)
AIISettings(0,O) "SaveSetting"
AIISettings(0,l) "k Works"
AIISettings(1)
AIISettings(1 ,0) "SaveSettingZ"
AIISettings(1 ,I) "k WorksZ"
AIISettings(2)
AIISettings(2,O) "SaveSettingS"
AIISettings(2,l) "k WorksS"

Adding a watch to the Allsettings variable allows us to see the structure


and values of the results of the GetAllSettings call.

READINGAND WRITING TO ASCII FILES


Give me a text file and I will move the world. Or is it supposed to be a
"Lever"? The ability to read and write ASCII text files gives us powerful
leverage in our programming efforts. Many programs and databases can
read and write these files. So, what are ASCII files?
An ASCII text file is composed entirely of ASCII characters. It can be
opened in Notepad or Wordpad and is readable by humans.

Sub TestWri teASCI IA( )


Open " C : \ o u t p u t . t x t " F o r O u t p u t As 81
P r i n t #l, " F i r s t l i n e . "
P r i n t #l, " S e c o n d l i n e . "
C l o s e #1 F i r 5 t 1 ine.
Second l i n e .
End Sub

Here is our file in Notepad. Let's examine


the code now.
First, identify a file with which to work. The above example works with
the file C:\output.txt. You can use any file extension but be careful. If you
write a new ASCII file and supply a file extension of.dgn, Microsoft
Windows will think it is a Microstation file and attempt to open it with
Microstation when you double-click on it.
You have two options to use when writing files. Use the "Output"
keyword, which means the file will be created if it does not exist or it will
I Reading and Writing to ASCII Files I 131

be overwritten if it does exist. Or use "Append if you want to add to the


end of an existing file or create a new file if one does not already exist.
When you open a file, a number is assigned to it. That number is then
used whenever you read from or write to the file. In the above example,
we are using a file number "#1". The number symbol must be in front of
the number each time it is used.
Next, write some text to the file. In the above example we use the P r i n t
function. You can also use the Write function (an example appears
below) but it gives slightly different results.
Last, C1 ose the file.

Sub TestWriteASCIIBO
Open " C : \ o u t p u t . t x t " F o r O u t p u t As #I
Write 111, " F i r s t l i n e . "
W r i t e 111, "Second l i n e . "
C l o s e 81 " F i r 5 t 1 i ne. "
"second l i n e . "
End Sub

The W r i t e function places quotation marks at the beginning and end of


each line which may be helpful if you need it.

Sub TestWri teASCI IC( 1


Open " C : \ o u t p u t . t x t " F o r Append As #I
Print 111, " A n o t h e r l i n e 1."
Print 111, " A n o t h e r l i n e 2 . "
Close 111 F i r 5 t 1 ine.
Second l i n e .
End Sub A n o t h e r l i n e 1.
A n o t h e r 1 ine 2 .

Use "For Append" when opening a file to


add text to an existing file. The above
screen shot is the result of running TestWri teASCI IA and then running
TestWriteASCIIC.

FreeFile
It is important to provide VBA a file number that points to the file in
which you want to work. In previous examples where I used "#1" as a
file number, the code works fine because the examples are simple. If
your programs open multiple files simultaneously, you could become
132 I Chapter 9: Standard VBA Calls I
confused as to which number should be used. This is where F r e e F i 1 e
comes in handy.

Sub TestWriteASCIIDO
D i m F F i l e A As L o n g
D i m F F i l e B As L o n g
FFileA = FreeFile
Open " C : \ o u t p u t a . t x t " F o r A p p e n d As # F F i l e A
P r i n t #FFileA, " A n o t h e r l i n e 1."
P r i n t #FFileA, "Another l i n e 2."
FFileB = FreeFile
Open " C : \ o u t p u t b . t x t " F o r A p p e n d As # F F i l e B
P r i n t IIFFileA, "Another l i n e 3."
P r i n t BFFileB, "Another l i n e 3."
P r i n t BFFileA, "Another l i n e 4."
P r i n t BFFileB, "Another l i n e 4."
C1 o s e # F F i 1 eB
C1 o s e # F F i 1 eA
End Sub

The above example works with two files at the same time. When you use
F r e e F i 1 e, assign the return value to a variable. In this example, I used
FFileA and FFileB as our variable names.

Be careful if you use F r e e F i 1 e for multiple variables as we have done


here. If you assign FFileA and FFileB file numbers with F r e e F i 1 e one
right after another, they will both hold the same value. F r e e F i 1 e returns
a different number only after a file has been opened. So, use F r e e F i 1 e,
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 "C:\Windows\System32" folder, as
well as the date and time the file was last modified. After the XML file is
written, you can open it in Microsoft Excel.
I Reading and Writing to ASCII Files I 133

Sub TestWriteASCIIEO
D i m F F i l e A As Long
D i m e x e F i l e As S t r i n g
FFileA = FreeFile
Open " c : \ e x e f i l e s . x m l " F o r O u t p u t As I I F F i l e A
P r i n t B F F i l e A , "<?xml v e r s i o n = " " l . O " " ? > "
P r in t {IFF i1 e A, " < ? ms o - a p p 1 ic a t ion p r o g id= " " Exc e 1 . S h e e t " " ? > " " "
P r i n t BFFileA, -

" <W o r k b o o k xm 1 n s= u r n : s c h ema s - m i c r o s o f t -


" " " & ~

"com:office:spreadsheet"">"

P r in t ]IF F i 1 eA , "
<Works hee t s s : Name= " " E X E F i 1 e s " " > "
P r i n t IIFFileA, " <Table>"
e x e F i 1e = D ir ( " C : \ W in d ow s \ Sys t e m 3 2 \ * . e x e " 1
While exeFile <> " "

P r i n t BFFileA, " <Row>"


P r i n t BFFileA, -

" <Cell><Data ss:Type=""String"">" & exeFile &


"</Data></Cell>"
P r i n t IIFFileA, ~

" <Cel l > < D a t a s s : T y p e = " " S t r i n g " " > " & -

F i 1 eDa t e T i me ( " C : \ W in d o w s \ S y s t e m 3 2 \ " & e x e F i 1e 1 & -


" < / D a t a > < / C e l 1> "
P r i n t BFFileA, " </Row>"
exeFile = Dir
Wend
P r i n t IIFFileA, " </Table>"
P r i n t IIFFileA, " </Worksheet>"
P r i n t IIFFileA, "</Workbook>"
Close FFileA
End Sub

Excel is particular about the


formatting of the XML
document, so if you encounter
problems copying this code
from this book, open and run
the code on the included CD.
Here is a portion of the results of
this XML file shown in Excel.
134 I Chapter 9: Standard VBA Calls I

Reading from ASCII Files


It is easy to write to ASCII files. Reading them is just as easy. Let's take it
one line at a time.

Sub ReadASCI IA( 1


D i m F F i l e As L o n g
D i m T e x t L i n e As S t r i n g
FFile = FreeFile
Open " C : \ M i c r o S t a t i o n VBA\TextPoints.txt" F o r I n p u t As # F F i l e
W h i l e EOF(FFi1e) = False
L i n e I n p u t B F F i 1e , T e x t L i n e
Debug.Print TextLine
Wend
C1 o s e # F F i 1 e
End Sub

1.5,2.5,O,Note 1
34.2,54.12,O,Note 2 1.5,2.5,O,NOte 1
34.2,54.12,O,Note 2
43.2,l. 43, 0,Note 3 43.2,1.43,O,NOte 3
22.3,33.4,O,Note 4
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 L i ne I n p u t 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 ReadASCIIBO
D i m F F i l e As L o n g
D i m T e x t L i n e As S t r i n g
D i m T e x t p o i n t As P o i n t 3 d
D i m X S p l i t As V a r i a n t
D i m T e x t E l e m As T e x t E l e m e n t
D i m R o t M a t As M a t r i x 3 d
FFile = FreeFile
Open " C : \ M i c r o S t a t i o n VBA\TextPoints.txt" F o r I n p u t As # F F i l e
W h i l e EOF(FFi1e) = False
L i n e I n p u t # F F i 1e , T e x t L i n e
XSplit = Split(TextLine, ",")
I Controlling Code Execution I 135

TextP0int.X = XSplit(0)
TextP0int.Y = XSplit(1)
TextP0int.Z = XSplit(2)
Set TextElem = Application.CreateTextElementl(Nothing, ~

XSplit(3), TextPoint, RotMat)


ActiveModel Reference.AddElement TextEl em
Wend
C1 ose BFFi 1 e
End S u b
We expanded ReadASCIIA. Now, instead of writing the information
from the text file to the Immediate window, lets create new text
elements at the X, Y,Z location specified in each line of text.

Here are our


notes placed
exactly where the
ASCII file
specified.

N 4

ot

CONTROLLINGCODEEXECUTION
It is essential that we know how to loop through code multiple times and
execute code based on certain conditions.
136 I Chapter 9: Standard VBA Calls I

For ...Next
When you know how many times to loop through a particular block of
code, use a For ... Next statement. Heres a simple example:

Sub ForNextA( 1
D i m I As Long
For I = 1 To 10
ActiveDesignFile.AddNewLeve1 NewLevel & I
Next I
End Sub
After this code is run, 10 new levels are created named NewLevel 1
through NewLevel 10:
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 of 2 (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 F o r N e x t B O
D i m I A s Long
For I = 1 To 1 0 S t e p 2
ActiveDesignFile.AddNewLeve1 NewLevelB & I
Next I
End Sub
I added an optional parameter to our For ... Next statement. It is a Step
parameter. By default, For ... Next loops increase the index parameter
by a value 1 (one) each time it is run. When this code is run, however,
I gets values of 1, 3, 5,7, 9, then ends with a value of 11 and exits the
loop because we are using Step 2:

Sub F o r N e x t C O
D i m I A s Long
For I = 1 0 To 1 S t e p - 1
ActiveDesignFile.AddNewLeve1 NewLevelC & I
Next I
End Sub
I Controlling Code Execution I 137

I just changed our Step parameter to -1. This means "I" 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 F o r N e x t D ( )
Dim X As D o u b l e
D i m Y As D o u b l e
D i m I n s P t As P o i n t 3 d
D i m C e l l E l e m As C e l l E l e m e n t
For X = 0 To 1 0 S t e p 0 . 2 5
For Y = 0 To 1 0 S t e p 0 . 2 5
1nsPt.X = X
1nsPt.Y = Y
Set CellElem = Application.CreateCellElement3("Column", -
InsPt, True)
ActiveModel Reference.AddElement C e l l Elem
Next Y
Next X
End Sub

This routine requires the definition of a cell named "Column" prior to


running it. Embed one For ... Next statement inside another. The Step
statement increases the variable by 0.25 each time it is executed. Note
that I declared our index variables as double so they can hold decimal
values.

While.. .Wend
When using Whi 1 e ... Wend we are uncertain how many times we need to
repeat a block of code. The code between the While and Wend
I Chapter 9: Standard VBA Calls I
statements continues to execute as long as the While statement is true.
Here is a portion of a procedure we already looked at in this chapter.

While EOF(FFi1e) = False


Line Input #FFi 1 e , TextLi ne
XSplit = Split(TextLine, " , " )
TextP0int.X = XSplit(0)
TextPoint .Y = XSpl i t(l)
TextP0int.Z = XSplit(2)
Set TextElem = Application.CreateTextElementl(Nothing, -

XSplit(31, TextPoint, RotMat)


TextEl em.TextSty1 e. Hei ght = 4
TextElem.TextStyle.Width = 4
ActiveModel Reference.AddE1 ement TextElem
Wend
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 TestDoWhi 1 eA( 1


Dim CadMsg As CadInputMessage
Dim InsPt As Point3d
Dim Cell El em As Cell Element
Do While True
Set CadMsg = CadInputQueue.Get1nput
Select Case CadMsg.InputType
Case msdCadInputTypeDataPoint
InsPt = CadMsg.Point
Exit Do
End Select
Loop
Set CellElem = Application.CreateCellElement3("Column", -

InsPt, True)
ActiveModelReference.AddElement Cell Elem
End Sub
I Controlling Code Execution I 139

One of the great things about a Do ... Loop statement is we can use Exit
Do to get out of the loop at any time. This example allows the user to
select a point in Microstation. When that happens, we capture the point
and exit the Do Loop. Then we use the captured point to insert a new
cell.
Here is another variation of the above procedure. In this next example,
the code will continue inserting cells until the user hits a key on the
keyboard.

Sub TestDoWhi 1 eB( )


D i m CadMsg As C a d I n p u t M e s s a g e
D i m I n s P t As P o i n t 3 d
D i m C e l l E l e m As C e l l E l e m e n t
Do W h i l e T r u e
S e t CadMsg = CadInputQueue.Get1nput
S e l e c t Case C a d M s g . I n p u t T y p e
Case m s d C a d I n p u t T y p e D a t a P o i n t
InsPt = CadMsg.Point
Set CellElem = -
Application.CreateCel1 Element3(Column,
InsPt, True)
A c t i v e M o d e l R e f e r e n c e . A d d E l e m e n t C e l l Elem
Case msdCadInputTypeCommand
E x i t Do
End S e l e c t
Loop
End Sub

When using Do While True, we remain in the loop until we either


E x i t Do or E x i t Sub or E x i t Function. E x i t Do to get out of the
loop and continue to execute the code in the procedure or function. Use
E x i t Sub and E x i t Function to exit the procedure or function.

Sub TestDoWhi 1 eC( )


D i m T e x t T o P l a c e As S t r i n g
D i m L i n e N u m b e r As Long
D i m N o t e P t As P o i n t 3 d
D i m CadMsg As C a d I n p u t M e s s a g e
D i m T e x t E l e m As T e x t E l e m e n t
D i m R o t M a t As M a t r i x 3 d
Do W h i l e T r u e
140 I Chapter 9: Standard VBA Calls I
S e t CadMsg = CadInputQueue.GetInput
S e l e c t Case C a d M s g . I n p u t T y p e
Case msdCadInputTypeDataPoint
NotePt = CadMsg.Point
S e t TextElem = Application.CreateTextElernentl(Nothing, -

B N o t e , N o t e P t , R o t M a t )
A c t i v e M o d e l Reference.AddE1 ement T e x t E l e m
E x i t Do
End S e l e c t
Loop
TextToPl ace = T h e f o l l o w i n g n o t e s s u p e r c e d e a1 1 p r i o r n o t e s .

LineNumber = 1
Do
N0tePt.Y = N0tePt.Y - 0.375
Set TextElem = Application.CreateTextElementl(Nothing, ~

LineNumber & I. & TextToPlace, ~

NotePt, RotMat)
A c t i v e M o d e l Reference.AddE1 ement T e x t E l e m
LineNumber = LineNumber + 1
TextToPlace = InputBox(Enter Note:)
Loop W h i l e TextToPl ace <> I

End Sub

This procedure uses two separate Do Loop statements. Lets 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
1. The following notes supersede all prior notes. below the # Note
text.
Now that we added a header and a standard note, we allow the user to
begin entering additional notes. Each additional note is placed 0.375
units below the prior note. When the user presses the OK button
without entering anything in the InputBox, the Loop completes because
TextToPlace is an empty string and the Loop condition is no longer
true.
I Controlling Code Execution I 141

For Each.. Next .


Some objects are in collections. For example, each document has a
Levels collection composed of Level objects. Use For Each ... Next
statements to look at each object in a collection.

Sub T e s t F o r N e x t A ( )
D i m d g n L e v e l As L e v e l
F o r Each d g n L e v e l I n A c t i v e D e s i g n F i l e . L e v e 1 s
D e b u g . P r i n t d g n L e v e l .Name
Next
End Sub
NewLevelC 3
When we use For Each ... Next, we NewLevelC 2
NewLevelC 1
specify a variable to use for each
object and then the collection to
look in when we begin the For
Each ... Next statement.

.
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 T e s t I f T h e n A ( 1
D i m L e v e l N a m e As S t r i n g
L e v e l Name = I n p u t B o x ( " E n t e r L e v e l Name ( 3 l e t t e r s o n l y ) " )
I f Len(Leve1Name) = 3 Then
A c t i v e D e s i g n F i l e . A d d N e w L e v e 1 L e v e l Name
End I f
End Sub

If the user enters something with three characters, add the new level. A
very simple implementation of an If.. . Then statement.

Sub T e s t I f T h e n B ( 1
D i m L e v e l N a m e As S t r i n g
L e v e l Name = I n p u t B o x ( " E n t e r L e v e l Name ( 3 l e t t e r s o n l y ) " )
I f Len(Leve1Name) = 3 Then
A c t i v e D e s i g n F i l e . A d d N e w L e v e 1 L e v e l Name
Else
142 I Chapter 9: Standard VBA Calls I
MsgBox L e v e l N a m e & " has " & Len(Leve1Name) & -
" characters."
End I f
End Sub

In this example, look at the number of characters and create the new
level if it is three characters in length. Also add an "Else" statement to
handle situations when the length is not equal to three. Display a
MessageBox showing the number of characters entered when the entry
has anything other than three characters in it.

Sub T e s t I f T h e n C ( )
D i m L e v e l N a m e As S t r i n g
LevelName = I n p u t B o x ( " E n t e r L e v e l Name ( 3 l e t t e r s o n l y ) " )
I f Len(LevelName1 = 3 Then
ActiveDesignFile.AddNewLeve1 L e v e l Name
E l s e I f Len(LevelName1 > 3 Then
A c t i v e D e s i g n F i 1 e.AddNewLeve1 L e f t ( L e v e l Name, 3 )
Else
MsgBox L e v e l N a m e & " h a s " & L e n ( L e v e 1 N a m e ) & -
" characters."
End I f
End Sub

TestIfThenC introduces an E l s e I f statement. You can use E l s e I f


statements inside I f ... Then statements and provide a secondary I f
statement. You can use multiple E 1 s e I f statements before an E 1 s e
statement.

Select Case
Imagine asking a user to enter a level name then looking at the first
character of the level name. You could use an I f ... Then statement with
multiple E l s e I f statements or a S e l e c t Case statement.
Sel e c t Case lets us provide the condition and then multiple possible
matches for the condition.

Sub T e s t S e l e c t C a s e A ( )
D i m L e v e l N a m e As S t r i n g
LevelName = I n p u t B o x ( " E n t e r L e v e l Name:")
S e l e c t Case U C a s e ( L e f t ( L e v e 1 N a m e . 11)
Case " A "
I Controlling Code Execution I 143

A c t i v e D e s i g n F i l e . A d d N e w L e v e 1 " A _ " & L e v e l Name


Case " B "
A c t i v e D e s i g n F i l e . A d d N e w L e v e 1 "B-B-" & L e v e l Name
Case OUC", WDW, WE"

A c t i v e D e s i g n F i l e . A d d N e w L e v e 1 "CDE-" & L e v e l Name


Case E l s e
MsgBox " N o t a v a l i d l e v e l name."
End S e l e c t
End Sub

In this example, look at the first 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, prepend 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( 1
On E r r o r GoTo e r r h n d
D i m L i n e L e n g t h As Double
LineLength = CDbl ( I n p u t B o x ( " E n t e r L i n e L e n g t h : " ) )
E x i t Sub

errhnd:
S e l e c t Case E r r . N u m b e r
Case 13 ' T y p e M i s m a t c h
MsgBox " L i n e L e n g t h s m u s t b e n u m e r i c . "
Err . C l e a r
End S e l e c t
End Sub

In TestErrorHndA, ask the user for a line length. As you write code
assume the user knows to enter a numeric value but if the user enters
144 I Chapter 9: Standard VBA Calls I
something like 10 meters: you run into problems. If you dont handle
the error, the user sees this:

As you become more experienced in programming, you are better able


to anticipate potential data entry problems and other issues that cause
errors.
So, if you do not handle the Type Mismatch
error when asking the user to enter a length, he
sees an unhandled error MessageBox. If the
users click the Debug button, he is taken to the
code that shows the line where the error
occurred. However, if you handle the error as
shown in the above macro, the user sees this:
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, lets take another look at the code in detail. The first thing to do in
the procedure is state:

On E r r o r GoTo e r r h n d

This tells VBA that if an error is encountered jump to the area of code
labeled errhnd: Here it is:

errhnd:
S e l e c t Case E r r . N u m b e r
Case 1 3 T y p e M i s m a t c h
MsgBox L i n e L e n g t h s m u s t b e n u m e r i c .
Err.Cl e a r
End S e l e c t
I Controlling Code Execution I 145

Each error has a number associated with it. Use a Select Case statement
to handle different types of errors differently. In this example, only look
at error number 13. If any other error occurs, it is not handled by our
Select 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. Lets go back to TestSelectCaseA covered a few
pages ago. Run that macro and enter aad: Everything should run fine.
Run it again and enter aad: What happens?

If you enter the same level name twice, the code attempts to create a
duplicate level. We see this MessageBox which gives us some good
information. First, it tells us the error number. -2147221504 and a
description that Level name is duplicate.That is good to know because
we can add that number in the error handling portion of our code. We
can also hit the Debug button to go to the line of code in question to see
exactly where the error occurs.

Sub TestErrorHndB( 1
On E r r o r GoTo e r r h n d
D i m LineLength As Double
LineLength = CDbl ( I n p u t B o x ( E n t e r L i n e L e n g t h : ) )
E x i t Sub

errhnd:
S e l e c t Case Err.Number
Case 13 T y p e M i s m a t c h
MsgBox L i n e L e n g t h s m u s t be n u m e r i c .
Err . C 1 e a r
Resume N e x t
End S e l e c t
End Sub
146 I Chapter 9: Standard VBA Calls I
TestErrorHndB isidenticalto TestErrorHndAexceptforoneline.Addinga
Resume Next statement in TestErrorHndB executes our procedure to
continue the line after the error occurred.

Sub T e s t E r r o r H n d C ( )
On Error GoTo e r r h n d
D i m L i n e L e n g t h As D o u b l e
LineLength = CDbl ( I n p u t B o x ( " E n t e r L i n e L e n g t h : " ) )
E x i t Sub

errhnd:
S e l e c t Case Err.Number
Case 1 3 ' T y p e Mismatch
MsgBox " L i n e L e n g t h s must be n u m e r i c . "
Err.Cl e a r
Resume
End S e l e c t
End Sub

Here is another slight modification that uses a Resume statement instead


of Resume Next. Resume asks VBA to again try the line of code where the
error occurred, whereas Resume Next ignores the line of code where the
error occurred and moves to the next line.

Sub T e s t E r r o r H n d D ( )
On Error Resume N e x t
D i m L i n e L e n g t h As D o u b l e
LineLength = CDbl ( I n p u t B o x ( " E n t e r L i n e L e n g t h : " ) )
End Sub

Instead of attempting to trap errors as they occur, you can tell VBA to
ignore errors altogether and move to the next line using "On Error
Resume Next".
Although "On Error Resume Next" appears to be somewhat sloppy (and
it can be), it can be useful. Consider this next procedure:

Sub T e s t E r r H n d E ( )
On Error Resume N e x t
D i m MyExcel As O b j e c t
S e t MyExcel = G e t o b j e c t ( , "Excel . A p p l i c a t i o n " )
I f Err.Number <> 0 Then
I Controlling Code Execution I 147

Err.Cl e a r
S e t MyExcel = CreateObject("Exce1 . A p p l i c a t i o n " )
End I f
On E r r o r GoTo e r r h n d
MyExcel . V i s i b l e = True
MsgBox MyExcel . A c t i v e S h e e t . N a m e
E x i t Sub

errhnd:
MsgBox "Error " & Err.Number & " has o c c u r r e d . " & vbCr & -
Err.Oescription, v b c r i t i c a l , " E r r o r I n TestErrHndE"
Err.Cl e a r
End S u b

In this example, we use On Error Resume Next because we are


anticipating the potential for a specific error.

S e t MyExcel = G e t o b j e c t ( , "Excel . A p p l i c a t i o n " )

G e t o b j e c t assumes the object we are getting has already been created by


starting Excel (in this example). If Excel is not started, however, we
normally get an error when using G e t o b j e c t . Use the Err object to get
error numbers and descriptions. After calling Getobject, check the
Err.Number value. If it is non-zero, an error occurred. Use Err.Clear to
clear the previous error from memory.
Then we move to the next method of working with Excel, using
C r e a t e o b j e c t which launches the Excel application. On Error GoTo
e r r h nd tells VBA to move to the "errhnd area if an error is encountered.
Set the Visible property of the Excel application to true. This can cause
an error if Excel did not start, most often because it isn't installed. If
Excel is running and visible, display the name of the active sheet in a
MessageBox. This can throw an error because even though Excel is
running, an Excel workbook (As file) file is not open.
Now to the errhnd section of our code. A review of the above suggests
that a number of things could cause errors. Showing the error number
and description in a MessageBox lets us know which error has been
raised.
148 I Chapter 9: Standard VBA Calls I
Sub TestErrorHndF()
On E r r o r GoTo e r r h n d
D i m L i n e L e n g t h As D o u b l e
On E r r o r GoTo 0
LineLength = CDbl ( I n p u t B o x ( " E n t e r L i n e L e n g t h : " ) )
E x i t Sub
errhnd:
MsgBox " E r r o r " & Err.Number & " has o c c u r r e d . " & vbCr & -

Err.Description, v b c r i t i c a l , " E r r o r I n TestErrHndE"


Err . C l e a r
End Sub

"On Error G o t o 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 fx the bug, you can comment out the "On Error G o t o 0"
line so your Error Handling code is at work again.
We covered a number,
although not a
comprehensive list, of
useful and commonly
used VBA calls. You can Cglobalsa
Collection
use the Object Browser ColorConstants
in VBA to display all Constants
...Conversion
VBA calls natively ..................................................
;DateTime
.....................................................
Errobject
available to us. We will Filesystem
discuss the Object Financia I
FormShowConstar
Browser later in this Global
book. Here is a snapshot Information
Interaction
of what you will see if KeyCodeConstantr
Math
you filter on the VBA
Reference, the DateTime
Class, and the D a t e D i f f
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 <F1> key.

DateDiff Function
See Also Example Speri!ics
Returns a Variant (Long) specifying the number of time intervals between two specified
dates.
Syntax
DateDiff(interva1, d a t e f , date2[. firstdayofweek[. firstweekofyear]])
The DateDiff function syntax has these named arsuments:

interval Required. Strins exmession that is the interval of time you


use to calculate the difference between datef and date2.

date1 , date2 Required; Variant (Date).Two dates you want to use in the
calculation.

firstda yofweek Optional. A constantthat specifies the first day of the week. If
not specified, Sunday is assumed.

firstweekofyear Optional. A constant that specifies the first week of the year.
If not specified, the first week is assumed to be the week in
which January 1occurs.

Settings
The interval arsument has these settings:

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 Savesetting and Getsetting procedures.
10 Visual Interface

It is time to begin working with the


Visual side of VBA. Lets consider the
form shown. It is composed of labels
(Level, Cells, X, Y, and Z), two combo
boxes (with SIDEWALK and column
selected), three text boxes (for X, Y, and
Z values), and two CommandButtons
labeled Insert and Cancel.
Creating a good graphical user interface
(GUI) can be one of the most
challenging elements of software development. Anyone can throw
buttons on a form, but making the interface user friendly and intuitive
takes thought, effort, and being open to the ideas of others.
Lets discuss the form shown above. The goal is to allow the user to
insert cells on a specific level at a specific point. Which should come
first? The Cell Name ComboBox? If we know which cell we want to
insert, perhaps it should appear first. What if the list of cells is
dependent on the selected level? This would keep us from inserting a
cell on the wrong level. So, perhaps the level should be first. Then we
have the insertion point. Perhaps it would be best if the insertion point
appeared after the level and cells combo boxes. And perhaps we should

151
152 I Chapter 10: Visual Interface I
allow the user to pick the insertion point in addition to being able to
enter the insertion point by hand. Lets move things around a little.
How does this look? Better? OK.
We have the visual elements
arranged now. After you create
the basic interface, you can
begin writing code behind the
interface. Well get into that a
little later. First, lets talk about
the controls we can add to our
user forms.
The toolbox shows us the controls we can place
on our forms. Except for the pointer arrow, each
of the items shown are visual elements we can use
in our interface design.

PROPERTIES, METHODS,
AND EVENTS
Controls have properties, methods, and events. A property describes
how a control looks or behaves. Methods tell controls to do something.
For example, using the ComboBox XddItem method adds an item to
its list. Most events occur when the user interacts with our GUI. For
example, when a user clicks a button, the click event of the button is
triggered and executes any code we place in that event.

Properties
You can set properties at design time (that is while you are designing
your interface and writing code) or at run-time (when the program is
being run). Control properties are modified at design time by using the
Properties window.
I Properties, Methods, and Events I 153

You can display or hide the Properties


window. If a CommandButton is
selected but you cannot see the
Properties window, right-click on the
button and select Properties from
the context menu or press the <F4>
key.

At run-time, properties can be set as follows:

CommandButtonl.Enabled = True
We enabled the control named CommandButtonl by setting its
Enabled property to true.
We can also get property values at run-time.

M s g B o x CheckBoxl.Value
NewLevel Name = txtLevel Name.Text
Notice how we begin by addressing the control by name, typing a
period, and then typing the property to work with. After you press the
period key, VBA shows a list of the available properties and methods.

Private Sub CommandButtonl-Click ( )


M s g B o x CheckBoxl. V a l u e
N e w L e v e l N a m e = t x t L e v e l N a m e .t e
End Sub
TexfAlign
TextLength
TOP
Value
Visible
Width

In the above example, I typed the name of a TextBox txtLevelName and


the period key so the helper window displays the available properties
and methods. As you begin typing the name of the property or method,
VBA automatically selects the first matching item in the list. When the
txtLevelName.tehas been typed, if you press the <Enter>VBA fills in
the rest of the text and moves to the next line. If you press the <Tab>,
VBA fills in the rest of the text and moves to the end of the current line
154 I Chapter 10: Visual Interface I
of code. Letting VBA finish our sentences lets us develop applications
very rapidly.

Control Events
Now, lets look at using control events. You write code for control events
in the forms 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 (CommandButtonl is selected below), we can then select
an event in the right-hand ComboBox (the click event is selected
below).

Private Sub CommandButtonl-Click ( )


MsgBox CheckBoxl. Value
End Sub

To work with a different event, simply drop down the procedure


ComboBox (on the right) and select another event. As we can see here,
there are quite a few events from which to choose.
I Common Control Properties I 155

When you select an event not previously selected, VBA fills in the
framework of the event for us.

Private Sub CommandButtonl-KeyPress(ByVa1 KeyAscii A s MSForms.Return1nteger)


I
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.

P r i v a t e S u b CommandButtonl-MouseDown(ByVa1 B u t t o n A s I n t e g e r , -
ByVal S h i f t AS I n t e g e r , -
ByVal x AS s i n g l e , ByVal Y AS s i n g l e )

End Sub

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.

COMMONCONTROLPROPERTIES
Before discussing each control individually, lets talk about properties
and events that nearly all controls have in common.
156 I Chapter 10: Visual Interface I

Name
Whats in a name? We work with controls by addressing them by name.
We then identify the property we want to get or set, or the method we
want to use. The name and property (or method) are separated by a
period. Take a look:

Labell.Caption = E n t e r L e v e l Name:

Change the Caption property of the control named Labell by calling


the control by name, typing a period, and then typing Caption which
is the property we want to modify When you want to SET a property
value, the Control.Property is on the left-hand side of the equal sign
and the value you are assigning it is on the right-hand side, as shown. To
GET the Control.Property: put it on the right-hand side of the equal
sign and place a variable on the left-hand side of the equal sign like this:

XVal = txtXValue.Text

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,O). So, if a TextBox is given a Left value of 0 and a Top value of
0, it appears in the upper left corner of the form.
I Common Control Properties I 157

Width, Height
All controls have Width and Height properties. These properties
determine the size of the control. We should consider the size and shape
of the controls we use. Just because a TextBox can have a width of 20 and
a height of 20 doesn't mean it should. If a TextBox is a set to be a single-
line TextBox, it may make little sense to have its height greater than is
necessary to display a line of text. If on the other hand, you want to
display a square CommandButton, make the width and height
properties the same.

Visible
Why would you want to place a control on a form and then set its Visible
property to false? Controls are to be seen, right? There are times when
you may want to make a control visible or invisible based on other
conditions. Setting a control's Visible property to false makes it invisible
at run-time but it is still visible at design-time. The Visible property can
be changed at run-time between true and false as needed.

Enabled
When a control has its Enabled property set to true, you can interact
with the control at run-time. When Enabled is false, the control turns
gray and you we are unable to interact with it. The Enabled property
does not affect the visibility of the control, only the interaction.

TabStop
Pressing the <Tab> key at run-time moves from control to control. If
the TabStop property of a control is true, the control receives focus in its
turn. If TabStop is false, the control does not receive focus during
tabbing.

Ta blndex
The TabIndex property determines the order in which controls receive
focus as you Tab from control to control.
158 I Chapter 10: Visual Interface I

Use the Tag property to do as you see fit. One thing you can do with the
tag is assign it a default value for a TextBox and give the user the ability
to click a Load Defaults button, causing the Tag property to populate
the Text property.

Cont rolTipText
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.

This example shows the ControlTipTextproperty value. An experienced


user learns that the level name should be four characters long, while new
users benefit from having a little help on what they should enter.
Enough with the common control properties. Lets talk about each of the
standard controls one at a time, highlighting its primary properties,
methods, and events. Also shown will be its icon in the toolbox.

Labe1
Labels help users know what to enter or select. Properties of note are as
follows:

Caption The text displayed to the user.


Font The font used to display the Caption.

TextBox
The TextBox allows users to enter text or display text, often in single-
line mode so text is displayed in one line. You can stretch a TextBox
vertically to display multiple lines.
I Common Control Properties I 159

Properties

Text
Locked
True: users cannot. When set to True; text in the
TextBox can be selected and copied to the Windows
Clipboard even though the text cannot be changed by
the user. When Locked, you change the text property

MaxLength

asking for a Canadian postal code, you could set the


MaxLength property to 6,to enter V4A5M2; but
would be prohibited from entering 85302-1 234:
MultiLine and
WordWrap next line. When False text is scrolled on one line.
Passwordchar
what is being typed, supply a password character.
Enter an asterisk (1 in this property to make an asterisk
appear each time a keyboard key is pressed. This can
keep others from seeing what is being typed (if they
are looking over our shoulder), but is not highlysecure.
It takes very little code for a seasoned developer to find
out exactly what is behind the password characters
displayed on screen.
160 I Chapter 10: Visual Interface I

Keypress Gives the ASCII code of the character pressed on


the keyboard. Use this to restrict users from
entering specific characters, such as allowing only
numeric values to be entered.
KeyDown, KeyUp Gives the keyboard key pushed down and released
as well as the state of the <Shift>,<Control>,
and <Alt> keys. For example, we know if the <F1>
key was hit by using the KeyDown or KeyUp event
but cannot see the <F1> key in the Keypress event
because it is not an ASCII character. This differs
from the Keypress event which tells which
character was pressed (A or a).

COMBOBOX
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 Text selected or entered in the ComboBox.


Style O=Combo (select from list or type into a ComboBox)
or 2=List (user must select from list).
Index of the selected item in ComboBox.
-1 = Nothing selected. 0 = First item in list is selected.
1 = Second item in list is selected and so on.
Number of items in the ComboBox.
I ListBox I 161

Methods

Addltem Adds a List Item to the ComboBox.


Remove1tem

Clear Clears all items from the ComboBox list.

Click Occurs when user clicks on an item in the ComboBox.


Change Occurs when the selected item changes. This is different
from the Click event because it is possible to change the
selected item in the ComboBox by using arrow keys and
other keyboard keys.

LISTBOX
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 Text of the Selected Item in the List.


MultiSelect
Selected
of the item we want to check on.
ColumnCount

Addltem Same as ComboBox


Removeltem
Clear
162 I Chapter 10: Visual Interface I

Click Same as ComboBox


Change

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 True or False. When true, CheckBox has possible values
of true, false, or null. When Triplestate is false, possible
values are either true or false.
Value

Events

Click When user clicks on a CheckBox, the value is set to either true
or false. Click events do not fire when the user clicks the
CheckBox and the value is set to Null (in Triplestate mode).
Change

OPTIONB m o ~
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.
I Toggle Button I 163

Properties

Caption
Group Name
selected. To allow a user to select "Large': "Medium':
"Small" for a size and to allow them to select "Red':
"White", "Blue" for the color, use two group names for
each group of OptionButtons.

Events

Click See CheckBox Click Event.


Change
DblClick This event is triggered when a user double-clicks the

BUTTON
TOGGLE
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 Text displayed on the Toggle Button.


TrippleState
Value

Events

Click See OptionButton.


Change
DblClick
164 I Chapter 10: Visual Interface I

FRAME
Frames are control containers. This means that controls can be placed
inside of them. If a frames 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 The Caption shown in the upper left-hand corner of the

Visible

Use CommandButtons to give users something to click on, such as these


(commonly captioned): OK,Cancel,Print,Open,and Close:

Properties

Caption Text displayed in the Button.


TakeFocusOnClick Determines whether the Button receives focus
when the user clicks the button or if focus remains
with the previously selected control.

Events

Click Triggered when the user clicks the button.

TABSTRIP
Use tab strips to present Tab selections. Do not confuse these with the
MultiPage Control even though they look alike. Tab strips are not
control containers. Rather tab strip buttons are a cross between toggle
buttons and OptionButtons. Only one tab on a tab strip can be selected
at any given time.
I MultiPage I 165

Properties

MultiRow When set to True, multiple rows are displayed when


the number of tabs exceeds the width of the Tab Strip.
When set to False, the Tabs are all displayed on one

Selectedltem Which tab is selected?


Style

TabOrientation

Methods

Ta bs.Add Used to add Tabs to the Tab Strip.

Events

Change Triggered when the active Tab changes.

MULTI
PAGE
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
MuItiRow

Methods

Pages.Add Used to add pages to the MultiPage control.


166 I Chapter 10: Visual Interface I

Events

Change

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 The amount the Value property changes when the


user clicks inside the ScrollBar area.
Smallchange
user clicks on the outside Scroll Bar Arrows.
Min
Scroll Bar is Horizontal.
Max The Maximum Value the Scroll Bar can have.
Value

Events

Change Triggered when the value changes by clicking in the Large


Change area or on the Small Change arrows and after the
Thumb is released.
Scroll

Label, for example, and do not implement the Scroll event,


the Label will not change until the Thumb is dropped. The
Scroll event allows us to see the number change as the

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.
167

Properties

Delay Time in milliseconds after the user begins holding


down a button before the value begins scrolling up or
down
Minimum Spin Button Value.
Max I
Small Change
Value The Value of the Spin Button.

Change
SpinUp
SpinDown

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 The file to display in the Image Control.
PictureSizeMode
PictureTiling
for no tiling.

USERINTERFACE
EXERCISES
We started this chapter by discussing the importance of creating a useful
and intuitive interface, then introduced the standard controls. Now lets
create a few interfaces to demonstrate the properties, methods, and
events we covered. To accomplish this, you will insert a few new forms
168 I Chapter 10: Visual Interface I
in a new project. Begin by inserting one new form and working with it.
After it is finished, insert another new form, and so forth.
Here is the first interface you are going
to work with. Add the controls
beginning at the top and working down.
The first controls are two ComboBoxes.
By default they are inserted with the
names ComboBox 1 and ComboBox2.
Change the names to cmbLevels and
cmbCells. Next, insert two labels and
place them on the left-hand side of the
ComboBoxes. Make the caption properties for these labels Level and
Cells.
The next section is a group of controls inside a frame. Insert the frame
and change the frame caption to Insertion Point. Then insert the text
boxes, labels, and CommandButton. Change the TextBox names to txtX,
txtY, and txtL Name the CommandButton cmdPick 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 I n it i a 1 ize in
the Procedure ComboBox.

Private Sub UserFormpInitializeO


Dim MyLevel As Level
Dim MyCellEnum As CellInformationEnumerator
Dim MyCell As Cell Information
For Each MyLevel In ActiveDesignFile.Levels
cmbLevels.AddItem MyLevel .Name
Next
Set MyCellEnum = -
Application.GetCellInformationEnumerator(True, True)
I User Interface Exercises I 169

Whi 1 e MyCell Enum.MoveNext


Set MyCell = MyCellEnum.Current
cmbCells.AddItem MyCell.Name
Wend
End Sub
Here is the code in the Initialize Event of the UserForm. It should look
like this:

Private Sub UserForm-Initialize 0


Dim MyLevel As Level
Dim MyCellEnum As CellInformationEnumerator
Dim MyCell As CellInformation
For Each MyLevel I n ActiveDesignFile.Leve1s
crnbLevels.Add1tern MyLevel.Narne
Next
Set MyCellEnum = Application. G e t C e l l I n f o r r n a t i o n E n u r n e r a t o r (True, True)
While MyCellEnum.MoveNext
Set MyCell = MyCel1Enum.Current
crnbCells.AddItern MyCell.Narne
Wend
End S u b

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 <F5> 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 type
anything into these two ComboBoxes. To accomplish this, change the
Style properties of the ComboBoxes to 2 - fmStyleDropDownList.
The next thing is to write some code so only numeric values can be
entered into the text boxes. Do this by working with the Keypress event
of the text boxes.
170 I Chapter 10: Visual Interface I
Right-click on the top TextBox and select View Code. This takes us to
the Change e v e n t of the TextBox by default. Selecting K e y p r e s s in the
Procedure ComboBox takes us to the K e y p r e s s e v e n t .

Private Sub txtX-Keypress (ByVal -


KeyAscii As MSForms. ReturnInteger)
Select Case KeyAscii
Case Asc("0") To Asc("9")
Case Asc ( " . " )
I f InStr(1, txtX.Text, " . " ) > 0 Then
KeyAscii = 0
End I f
Case Else
KeyAscii = 0
End Select
End Sub

"KeyAscii" is passed to us in the Keypress event. It tells us the ASCII


value of the character that was pressed. If the ASCII code is for the
numbers 0 through 9, the code will do nothing to the KeyAscii
parameter. This allows the value to be entered into the TextBox just as it
was typed.
Next look at the period symbol. If there is already a period in the
TextBox, set KeyAscii to zero which keeps another period from being
entered. If a period is not in the TextBox, do nothing to the KeyAscii
parameter so the period can be added.
If any other KeyAscii value is encountered, set the KeyAscii parameter
to zero (0) which causes the event to act as though nothing was pressed.
We need to put the same code into the K e y p r e s s 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.

P r i v a t e Sub t x t X L K e y P r e s s ( B y V a 1 -

K e y A s c i i As M S F o r r n s . R e t u r n 1 n t e g e r )
S e l e c t Case K e y A s c i i
Case A s c ( " 0 " ) To A s c ( " 9 " )
Case A s c ( " . " )
If InStr(1, txtX.Text, "."I > 0 Then
I User Interface Exercises I 171

KeyAscii = 0
End If
Case Else
KeyAscii = 0
End Select
End Sub

Private Sub txtYLKeyPress(ByVa1 -


KeyAscii As MSForms.Return1nteger)
Select Case KeyAsci i
Case Asc("0") To Asc("9")
Case Asc(".")
If InStr(1, txtY.Text, " . " ) > 0 Then
KeyAscii = 0
End If
Case Else
KeyAscii = 0
End Select
End Sub

Private Sub txtZLKeyPress(ByVa1


KeyAscii As MSForms.Return1nteger)
Select Case KeyAsci i
Case Asc("0") To Asc("9")
Case Asc(".")
If InStr(1, txtZ.Text, " . " ) > 0 Then
KeyAscii = 0
End If
Case Else
KeyAscii = 0
End Select
End Sub
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 cmdCance1-Click0


Unload Me
End Sub
172 I Chapter 10: Visual Interface I
One line of code is all it takes to close the form.
That's it for the easy functionality; now for something more difficult.
When a user clicks the CommandButton, insert the selected cell on the
selected level at the entered insertion point.

Private Sub cmdInsert-Cl ick(


If cmbLevels.Text = Then
" "

MsgBox "Please select a level . "


Exit Sub
End If
If cmbCells.Text = Then
"I'

MsgBox "P1 ease select a cell . "

Exit Sub
End If
Dim InsPt As Point3d
Dim Cell El em As Cell Element
1nsPt.X = CDbl(txtX.Text)
1nsPt.Y = CDbl(txtY.Text)
1nsPt.Z = CDbl(txtZ.Text)
Set CellElem = CreateCellElement3(cmbCells.Text, InsPt, True)
Cell Elem. Level = ActiveDesignFi 1 e. Level s(cmbLeve1 s .Text)
ActiveModelReference.AddElement Cell Elem
End Sub
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
the "Insert" button after clicking the "PICK" button.
I User Interface Exercises I 173

In short, we want the user to click inside Microstation. This could


present a problem because, by default, VBA forms are modal. That is,
the form is active and thus prevents us from interacting with
Microstation until the form is unloaded. To get around this potential
problem, display the form as modeless.

Sub DoCellInsertionO
frmCellInsertion.Show vbModeless
End Sub
Place DoCellInsertion in a code module where it will be used to
display our form.
Now for the PICK CommandButton, we want the user to pick a point.
If the Level and Cell ComboBoxes are not empty, insert the selected cell
on the selected level at the selected point.

Private Sub cmdPick-Click0


Dim MyMsg As CadInputMessage
Dim MyClue As CadInputQueue
Dim SelPt As Point3d
Dim CellElem As CellElement
On Error GoTo errhnd
Set MyClue = Application.CadInputQueue
Do
Set MyMsg = MyQue.GetInput
Select Case MyMsg.InputType
Case m s d C a d I n p u t T y p e D a t a P o i n t
SelPt = MyMsg.Point
txtX.Text = Se1Pt.X
txtY.Text = Se1Pt.Y
txtZ.Text = Se1Pt.Z
If cmbLevels.Text <> And cmbCells.Text <> Then
Set Cell El em = ~

CreateCellElement3(cmbCells.Text, -
SelPt, True)
Cell El em. Level = -
ActiveDesignFi 1 e. Level s(cmbLeve1 s .Text)
ActiveModel Reference.AddElement Cell Elem
End If
Exit Do
Case Else
Exit Do
174 I Chapter 10: Visual Interface I
End S e l e c t
Loop
E x i t Sub

errhnd:
Err . C l e a r
End Sub

Lets look through the code slowly. First, we declare some variables.
Thats the easy one. Second, we begin listening to the Input Queue. If the
user picks a point, we do the following:
Place the selected X, Y, and Z point elements into the three text
boxes.
If both the Levels ComboBox and Cells ComboBox are not
empty, insert the selected cell at the selected point and then
change its Level property to reflect the selected level.
If any other Input occurs or an error occurs, we exit the procedure.
If there is any concern about typing in all of the code shown for this
project, the VBA Project named ChapterlO.mvba can be found on the
CD included with this book.

POINT LISTREADER
This program concentrates on the ListBox control. Use the AddItem
method to add items to the ListBox. Then use the List property to place
values in the other columns of the ListBox. Use Remove to allow the
user to manually remove items from the ListBox.
We read a text file to get the points
into the ListBox of our interface.
The text file looks like this:
I Point List Reader I 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.

Here is the interface.

We are using two labels, one TextBox named txtPointFile, a ListBox


named IstPoints, and four CommandButtons named btnRead,
btnRemove, btnPlotPoints, and btnCancd.
ListBoxes, by default, use only one column. We want four columns, so
set the ColumnCountproperty to 4.Specify the width of each column
in the ColumnWidths property using the value 60 pC60 pC60 pt;60 pt:
Set the last property, MultiSelect,to 2 - fmMultiSelectExtended:This
allows the user to select multiple items in the list by using the <Shift>
and <Control>keys while clicking on items in the listbox.
Its time now to look at the code beginning with the Read button.

Private Sub btnRead-Click0


Dim PointText A s String
Dim Pointsplit A s Variant
Dim FFile A s Long
FFile = FreeFile
Open txtPointFile.Text For Input A s #FFile
While EOF(FFi1e) = False
Line Input #FFile, PointText
If PointText <> Then

Pointsplit = Split(PointText, , I
176 I Chapter 10: Visual Interface I
1stPoints.AddItem PointSplit(0)
1 stPoints. List(1 stPoints. ListCount - 1 , 1) = PointSpl i t(l)
lstPoints.List(1stPoints.ListCount ~ 1, 2) = PointSplit(2)
lstPoints.List(1stPoints.ListCount ~ 1 , 3) = 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 AddItem to add the X component of the
point. AddItem is only used to add items to the first column of the
ListBox. Each additional columns 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.

Private Sub btnRemove-Cl ick(


Dim I As Long
For I = 1stPoints.ListCount T o 1 Step - 1
If lstPoints.Selected(1 - 1) Then
1stPoints.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 Sub btnPlotPoints-Click0


Dim TextIns As Point3d
Dim TextVal As String
Dim I As Long
Dim PT As TextElement
Dim RotMat As Matrix3d
For I = 1 T o 1stPoints.ListCount
Text1ns.X = lstPoints.List(1 - 1 , 0)
Text1ns.Y = lstPoints.List(1 - 1 , 1)
I Write Out File I 177

Text1ns.Z = lstPoints.List(1 - 1 , 2 )
Set PT = Application.CreateTextElementl(Nothing, -
lstPoints.List(1 - 1 , 3 ) , TextIns, RotMat)
ActiveModel Reference.AddElement PT
Next I
End Sub
The btnPlotPoints button looks at each item in the list and from it we
get the X, Y, and Z elements of the text origin as well as the text to
display.
When the user clicks the Cancelbutton, execute the following code:

Private Sub btnCance1-Click0


Unload frmPointList
End Sub
Thats 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 D o P o i n t L i s t R e a d e r O
frmPoi ntLi st. Show
End Sub
The macro 0o Po int L is t Re a d e r is now used to display the form and all of
the great functionality we have just put in.

WRITE OUT FILE


The next macro we are
going to write utilizes
CheckBoxes and
OptionButtons. Heres the
visual interface:
178 I Chapter 10: Visual Interface I
We have seven CheckBoxes named chklevels, chklinestyles,
chkTextStyles, chkViews, chkAuthor, chkSubject, and chkTitle. We
also have two OptionButtons named optASCII and optHTML. To round
things out, we have two CommandButtons named cmdOK and
cmdCancel.
We want to allow the user to select any of the "Items To Write".
CheckBoxes are perfect for this.
As for the file format, only one selection should be made. This is why we
use OptionButtons.
Before we get into the code, it is important to understand that this
program is not as simple as the previous ones. Let's plan before we jump
in.
We want to write to two file formats: ASCII and HTML. This meets our
needs today but what about tomorrow? We should think about future
uses as we develop applications to allow for scalability. We could place
all of the code in the C1 ic k e v e n t of the cmdOK button, however,
breaking the code into more manageable chunks makes it easier for us to
add file formats tomorrow.
Let's look at three procedures for writing the file sections: headers, lines,
and footers.

Sub P r i n t H e a d e r ( H e a d e r 1 n As S t r i n g , F i l e N u m As L o n g , ~

O p t i o n a l C o l u m n s As L o n g = 1)
I f optASCII.Value = T r u e Then
P r i n t #FileNum, "['I & HeaderIn & "I"
E l s e I f optHTML.Value = T r u e Then
P r i n t BFileNum, " < t a b l e width=660>"
P r i n t B F i 1 eNum, " < t r > < t d c o l s p a n = " & C o l u m n s & -
" a1 i g n = c e n t e r > < b > " & H e a d e r I n & " < / t d > < / t r > "
End f
End Sub

Use an I and E 1 s e I f statement to handle the two file formats for today.
Another E l seI f statement is all it takes to add another file format
tomorrow.

Sub P r i n t L i n e ( L i n e 1 n As S t r i n g , F i l e N u m As L o n g )
I f optASCII.Value = T r u e Then
P r i n t #FileNum, LineIn
I Write Out File I 179

E l s e I f optHTML.Value = T r u e Then
D i m X S p l i t As V a r i a n t
D i m I As L o n g
XSplit = Split(LineIn, vbTab)
P r i n t #FileNum, "<tr>"
F o r I = L B o u n d ( X S p 1 i t ) To U B o u n d ( X S p 1 i t )
P r i n t #FileNum, vbTab & " < t d > " & X S p l i t ( 1 ) & " < / t d > "
Next I
P r i n t #FileNum, "</tr>"
End I f
End Sub

Use the procedure Pri n t L i ne for each of the selected items found. Use
another I f and E 1 s e I f statement for the file formats.

Sub P r i n t F o o t e r ( F i 1 e N u m As L o n g )
I f optHTML.Value = T r u e Then
P r i n t BFileNum, " < / t a b l e > " & vbCrLf
End I f
End Sub

We only need to print a footer if the HTML option is selected.


Now it is time to look at the C1 ic k E v e n t of the cmdOK button. There
are two sections in the C1 ic k Event. The first sets up the export. The
second section is a series of If ... Then statements, each directly related
to a CheckBox. Here it is:

P r i v a t e Sub c m d O K L C l i c k 0
D i m M y F i l e As S t r i n g
D i m F F i l e As L o n g
D i m m y L e v e l As L e v e l
D i m m y L S t y l e As L i n e S t y l e
D i m m y T S t y l e As T e x t S t y l e
D i m m y V i e w As V i e w
FFile = FreeFile
I f optASCII.Value = T r u e Then
MyFile = "c:\output.txt"
E l s e I f optHTML.Value = T r u e Then
MyFile = "c:\output.htm"
End I f
Open M y F i l e F o r O u t p u t As # F F i l e
P r i n t H e a d e r " F I L E NAME", FFile, 1
I Chapter 10: Visual Interface I
P r i n t L i n e A c t i v e D e s i g n F i 1 e . F u l l Name, F F i 1 e
PrintFooter FFile

If chkLevels.Value = T r u e Then
P r i n t H e a d e r "LEVELS", FFile, 3
F o r Each m y L e v e l I n A c t i v e D e s i g n F i l e . L e v e l s
P r i n t L i n e myLevel.Name & v b T a b & -

myLevel . D e s c r i p t i o n & vbTab & -

myLevel .E l ementCol o r , F F i l e
Next
PrintFooter FFile
End I f

If chkLineStyles.Value = T r u e Then
P r i n t H e a d e r " L I N E STYLES", FFile, 2
F o r Each m y L S t y l e I n ActiveDesignFile.LineStyles
P r i n t L i n e myLStyle.Name & vbTab & ~

myLStyle.Number. FFile
Next
PrintFooter FFile
End I f

If chkTextStyles.Value = T r u e Then
P r i n t H e a d e r "TEXT STYLES", FFile, 3
F o r Each m y T S t y l e I n ActiveDesignFile.TextSty1es
P r i n t L i n e myTStyle.Name & vbTab & -

m y T S t y l e . C o l o r & vbTab & ~

myTStyle.BackgroundFillColor, F F i l e
Next
PrintFooter FFile
End I f

I f chkViews.Value = T r u e Then
PrintHeader "VIEWS", FFile, 5
F o r Each myView I n A c t i v e D e s i g n F i 1 e . V i e w s
P r i n t L i n e myView.0rigin.X & vbTab & -

myView.0rigin.Y & vbTab & -

m y V i e w . 0 r i g i n . Z & vbTab & ~

myView.CameraAng1e & v b T a b & -

myview. CameraFocal L e n g t h , F F i l e
Next
I Write Out File I 181

PrintFooter FFile
End I f

I f chkAuthor.Value = T r u e Then
P r i n t H e a d e r "AUTHOR", FFile
PrintLine ActiveDesignFi le.Author, F F i 1e
PrintFooter FFile
End I f

I f chkSubject.Value = T r u e Then
P r i n t H e a d e r "SUBJECT", FFile
PrintLine ActiveDesignFi le.Subject, F F i 1e
PrintFooter FFile
End I f

If chkTitle.Value = T r u e Then
PrintHeader "TITLE", FFile
P r i n t L i n e A c t i v e D e s i g n F i l e . T i t l e , F F i 1e
PrintFooter FFile
End I f
C1 o s e # F F i 1 e
End Sub

We have saved the easiest event for last.

P r i v a t e Sub c r n d C a n c e l L C l i c k 0
Unload frrnWriteDgnSettings
End Sub

We add the following procedure to a Module to display the Form.

Sub D o W r i t e O u t F i l e O
frrnWriteDgnSettings.Show
End Sub
182 I Chapter 10: Visual Interface I

ZOOM AND PAN


Here is a little program that provides real-time interactive panning and
zooming of the views of the ActiveDesignFile.

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.

This is what the


MultiPage looks like
when a right-click is
performed on an
existing page.

Lets start with the Initialize event of the User form.

Private Sub UserForm-Initialize0


Dim ViewCen As Point3d
Dim MyView As View
For Each MyView In ActiveDesignFile.Views
cmbViews.AddItem MyView.Index
Next
I Zoom And Pan I 183

cmbViews.ListIndex = 0
ViewCen = ActiveDesignFile.Views(l).Center
scrX.Value = ViewCen.X
scrY.Value = ViewCen.Y
End Sub
Here is the Initialize event of the UserForm. We add each Views Index
to the ComboBox named cmbviews. Select the first element by
assigning the ListIndex value to 0. 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
sr cY.
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 SetZoom(ZoomVa1 ue As Long, OldZoomVal ue As Long)


ActiveDesignFile.Views(cmbViews.Text).Zoom 1 + -
(ZoomValue - OldZoomValue) / 100
ActiveDesignFile.Views(cmbViews.Text).Redraw
End Sub

Sub SetPan(XPan As Long, YPan As Long)


Dim Vieworigin A s Point3d
View0rigin.X = XPan
View0rigin.Y = YPan
View0rigin.Z = 0
ActiveDesignFile.Views(cmbViews.Text).Center = Vieworigin
ActiveDesignFile.Views(cmbViews.Text).Redraw
End Sub
When we use the zoom method of a view, providing a number greater
than 1 zooms in. A number less than 1 zooms out. The Zoom Method
zooms relatively. If we provide a zoom factor of 1.1 three times, the view
zooms in each time. Subtract the previous value from the current value
and divide the result by 100. Add that value to the number 1. This allows
us to zoom in and out as we move the scroll bar left and right. After
performing the zoom, issue a Redraw to see the result of the zoom.
184 I Chapter 10: Visual Interface I
Panning is performed by adjusting the views center.
You can see the code that is used to zoom in and out. Now lets look at
the events that call these procedures.

P r i v a t e Sub s c r Z o o m - C h a n g e 0
SetZoom scrZoom.Value, scrZoom.Tag
scrZoom.Tag = scrZoom.Value
End Sub

P r i v a t e Sub s c r Z o o m - S c r o l l 0
SetZoom scrZoom.Value, scrZoom.Tag
scrZoom.Tag = scrZoom.Value
End Sub

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, lets talk about panning. We are using two scroll bars to set the X
and Y elements of the views center.

P r i v a t e Sub s c r X L C h a n g e 0
SetPan s c r X . V a l u e , scrY.Value
End Sub

P r i v a t e Sub s c r X L S c r o l 1 ( 1
SetPan s c r X . V a l u e , scrY.Value
End Sub

P r i v a t e Sub s c r Y - C h a n g e 0
SetPan s c r X . V a l u e , scrY.Value
End Sub

P r i v a t e Sub s c r Y - S c r o l l (1
SetPan s c r X . V a l u e , 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:
All controls have properties, methods, and events.
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.
At run-time, events are triggered as the user interacts with your
interface.
Display user forms using the Show method.
Use the Initialize event to set values and populate controls prior
to the form being displayed.
11 The Microstation Object
Model - Objects

Objects are the basis for much of our VBA programming. Object
Models are hierarchal structures of objects. Rather than examine in this
chapter all of the objects, we will look at the tools available to work with
the Microstation Object Model. After we look at the tools, we will look
at some of the Objects frequently used when working with Microstation
VBA.

In this Chapter:
The Object Browser
Auto List Members
i
l The Microstation VBA Help File
El Adding Watches
The Microstation Object Model

187
188 I Chapter 11:The Microstation Object Model - Objects I

BROWSER
THEOBJECT
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
Object Browser
Browser. The Object Browser can also be displayed by using the VBA
menu View > Object Browser or by pressing the <F2> key on the
keyboard.

eglobals> ACSManager
AccuDrawHints ActiveDesignFile
ACSManaaet ActiveModelReference
ActiveSettings
ApplicationElement ActiveWorkspace
ApplicationObjectConnector AddAttachmentEventsHandler
ArcElement AddChangeTrackEventsHandler
AreaPattern AddLevelChangeEventsHandler
Attachment AddModalDialogEventsHandler
Attachments AddModelActivateEventsHandler
AuxiliaryCoordinateSystemElement AddModelChatigeEventsHandler
B s p Ii n e AddSaveAsEventsHandler
BsplineCuns AddViewUpdateEventsHandler
BsplineCunsElement AppendXDatum
Bspline Surface ApplyHorizontalScalingFixForEMF
BsplineSurfaceElement ApplplerticalScalingFixForEMF
CadlnputMessage AssembleComplexStringsAndShapes
CadlnputQueue Atn2

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
Name
Members of Application
OnDesignFileClosed
show up in the Members
0nDe s ig nF i Ie 0pene d
ListBox. The Members
0penDe s ig nF iIe
ListBox displays the
0penDe s ignF iIe F orP ro gra m
Properties, Methods, and
Path
Events of the selected Class.
Pi
I The Object Browser I 189

Three primary member types are shown in the Members ListBox.


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.
E

The Declaration shows us the Parameters for the Function or Procedure


as well as the return value type of Functions.
In addition to clicking on the Classes and Members we are familiar with,
we can search Object Models using the Object Browser.

Notice the cursor over the Hide/Show Search Results button in the
Object Browser. A search for text in the MicroStationDGN Trpe
Library results in numerous results. So, if we do not know the specific
Class or Member we need, we can use the Object Browser to search
for it.
190 I Chapter 11:The Microstation Object Model - Objects I

AUTO LIST MEMBERS


VBA gives us help as we write our code at design time.
Dim M y A p p A s A p p l i c a t i o n
Set M y A p p = A p p l i c a t i o n
M s g B o x myapp.
End S u b

The List Members list displays as we work in VBA. Once the list
displays, we can use the arrow keys and page up/down keys to scroll
through the list. If we select ActiveDesignFileat this time and press the
period key, we see the following:
Dim MyApp As Application
Set MyApp = Application
MsgBox myapp.ActiveDesignFi1e.
End S u b

The Xuto List Members list allows us to drill down through an Object
Model.

MICROSTATION
VBA HELPFILE
If we see something in the Object Browser and would like to see more
detail on it, we can select it in the Object Browser and press the <F1>
key on the keyboard. We are then presented with information about the
I Microstation VBA Help File I 191

Object, Property, Method, or Event that was selected in the Object


Browser.

Once in the Microstation VBA Help File, we can click on the Index tab
and type Xpplication Structure in the Search box. Selecting
Xpplication Structure from the Index list displays the Microstation
Application Object structure. Select Application Object from the list to
display a description of the object with hyperlinks to Properties,
Methods, Events, Example Code, and See Also which displays a list of
associated objects.
192 I Chapter 11 :The Microstation Object Model - Objects I

ADDINGWATCHES
We have introduced adding Watches previously. Adding a watch to a
variable is an excellent way to see its Properties. Some of the Properties
are actually other objects that we can continue to traverse by expanding
the item in the tree. Others in the list are Collections of Objects that we
can examine in the Watch window.

ACSManager ACSManagerlACSManageI
ActiveDesignFile DesignFileDesignFile
ActiveModelReference ModelReferenceYodelRefi
ActiveSetLings Settingslsetlings
Activeworkspace WorkspacelWorkspace
AltachedCellLibrary <No cell libraryr CellLibrary
Bspline BsplineiBspline
CadlnputQueue CadlnputQueuelCadlnputOl
Caption "chapter11.dgn (20 - V8 DON) - Microslation V8 XM Edition" String
CommandState CommandStatelCommandS
CurrerdGraphicGreup 1 Long
Cursorhiormatnn cwsormiormatiOnlCursorlr
ExecutingVBProject ObjedNBProjed
FullName "C:Wogram Files~entleyVulicroStatien~~~ion
exe" String
HasActiveDesignFile True Boolean
HasAdiveModelReference True Boolean
Height 1208 Long
IsAcademicVersian False Boolean
IsCellLibraryAttached False Boolean
IsRegidered True Boolean
IsSerialized True Boolean
KeyinArguments String
LeitPosnion -4 Long
MdlLib MdlLibraryYdlLibrary
Messagecenter MessageCerderYessageC
Name '"ustation" String
Path '"C:.DrogramFiles~entleyVulicroStation" String
ProcesslD 3160 Long
RasterManager RasterManagerIRasterMan
StandardsCheckerCordroller StandardsCheckerCordrollt
TapPosition -4 Long
UserName '"Administrator" String
VBE ObjectNBE
Version "Version 08.09.00.92Wlndows x 8 6 String
Visible True Boolean
Wdth 1608 Long

THEMICROSTATION MODEL
OBJECT
Let's begin looking at the Microstation Object Model by examining the
Application Object.
I The Microstation Object Model I 193

Application Object
The Application Object points to the Microstation Application.

Accessors

Sub TestAppl i c a t i o n A o
D i m M y A p p A s New A p p l i c a t i o n
M s g B o x MyApp.Path
End S u b

Sub TestAppl i c a t i o n B 0
Dim MyApp As Application
Set MyApp = Application
M s g B o x MyApp.Path
End S u b

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 Applications 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 TestAppl i c a t i o n C 0
M s g B o x Application.Path
End S u b

In this example, we have not declared any variables or set any variables.
We just use the Object named ?Applicationbecause 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. Lets take a look at a selection of the
Properties and Methods of a few of the Objects we deal with on a regular
194 I Chapter 11:The Microstation Object Model - Objects I
basis in Microstation. Some read-only properties are marked with
{read-only}.

Application
Property ACSManager As ACSManager {read-only}
Property ActiveDesi gnFi 1 e As Desi gnFi 1 e {read-
only1
Property ActiveModelReference As
ModelReference {read-only}
Property Activesettings As Settings {read-
only1
Property Activeworkspace As Workspace {read-
only1
S u b AddAttachmentEventsHandler(EventHand1er As
IAttachmentEvents)
S u b AddChangeTrackEventsHandler(EventHand1er
As IChangeTrackEvents)
S u b AddLevelChangeEventsHandler(EventHand1er
As ILevelChangeEvents)
S u b AddModalDialogEventsHandler(EventHand1er
As IModal Dial ogEvents)
S u b AddModelActivateEventsHandler(EventHand1er
As IModelActivateEvents)
S u b AddModelChangeEventsHandler(EventHand1er
As IModelChangeEvents)
S u b AddSaveAsEventsHandler(EventsHand1er As
ISaveAsEvents)
S u b AddViewUpdateEventsHandler(EventHand1er As
IViewUpdateEvents)
S u b AppendXDatum(XData0 As XDatum, Type As
MsdXDatumType, Value As Variant)
Function
ApplyHorizontal Scal i n g F i x F o r E M F ( P i x e 1 C o o r d i n a t
e As Double) As Long
Function
Applyvertical Scal i n g F i x F o r E M F ( P i x e 1 C o o r d i n a t e
As Double) As Long
Function
Assembl eCompl exStri ngsAndShapes (Chai nab1 eEl eme
n t s 0 As ChainableElement, CGapTolerance As
Double = -11 As El ementEnumerator
I The Microstation Object Model I 195

F u n c t i o n A t n 2 ( Y As D o u b l e , X As D o u b l e ) As
Double
Sub A t t a c h c e l l L i b r a r y ( C e l 1 L i b r a r y N a m e As
S t r i n g , CConvertFromV7 As MsdConversionMode =
msdConversionModeAlwaysl)
P r o p e r t y A t t a c h e d C e l 1 L i b r a r y As C e l l L i b r a r y
{ read-on1y 1
P r o p e r t y B s p l i n e As B s p l i n e { r e a d - o n l y }
F u n c t i o n B y C e l l C o l o r O As Long
F u n c t i on B y C e l l L i n e S t y l e ( ) As L i n e S t y l e
F u n c t i on B y C e l l L i neWei g h t ( As Long
F u n c t i o n B y L e v e l C o l o r O As Long
F u n c t i on By L e v e l L i n e S t y l e ( As L i n e S t y l e
F u n c t i o n B y L e v e l L i n e w e i g h t ( ) As Long
P r o p e r t y C a d I n p u t Q u e u e As C a d I n p u t Q u e u e
{ read-on1y 1
P r o p e r t y C a p t i o n As S t r i n g
P r o p e r t y Commandstate As Commandstate { r e a d -
only}
Function
ConstructCirclesTangentToThreeElements(E1ement
1 As E l e m e n t , E l e m e n t 2 As E l e m e n t , E l e m e n t 3 As
E l e m e n t , Temp1 a t e As E l e m e n t , [ O u t p u t T y p e As
MsdTangentElementOutputType =
msdTangentCi r c l e s l ,
CSamplesCount As Long = 1 0 1 ) As
E l ementEnumerator
Sub Copy D e s i g n F i 1 e ( E x i s t i n g D e s i g n F i 1 eName As
S t r i n g , NewDesignFileName As S t r i n g ,
COverwri t e As Boo1 e a n l )
Function
CreateApplicationElement(Application1D As
Long, A p p l i c a t i o n D a t a As D a t a B l o c k ) As
A p p l ic a t i o n E l ement
F u n c t i o n C r e a t e A r c E l e m e n t l ( T e m p 1 a t e As
E l e m e n t , S t a r t P o i n t As P o i n t 3 d , C e n t e r p o i n t As
P o i n t 3 d , E n d p o i n t As P o i n t 3 d ) As A r c E l e m e n t
F u n c t i o n C r e a t e A r c E l ement2(Templ a t e As
E l e m e n t , C e n t e r P o i n t As P o i n t 3 d , P r i m a r y R a d i u s
As Doubl e , S e c o n d a r y R a d i us As Doubl e , R o t a t i on
196 I Chapter 11 :The Microstation Object Model - Objects I
As Matri x3d, StartAngl e As Doubl e, SweepAngl e
As Double) As ArcElement
Function CreateArcElement3(Template As
Element, StartPoint As Point3d, PointOnCurve As
Point3d, Endpoint As Point3d) As ArcElement
Function CreateArcElement4(Template As
Element, StartTangent As Ray3d, Endpoint As
Point3d) As ArcElement
Function CreateArcElement5(Template As
Element, Chord As Segment3d, ArcLength As
Doubl e , P1 anePoi nt As Poi nt3d) As ArcEl ement
Function CreateAreaPattern(R0wSpacing As
Double, ColSpacing As Double, Angle As Double,
CellName As String, Scale As Double) As
AreaPattern
Function CreateBsplineCurveElementl(Temp1ate
As Element, Curve As BsplineCurve) As
Bspl i neCurveEl ement
Function CreateBspl i neCurveEl ementZ(Temp1 ate
As El ement, Curve As Interpol ati oncurve) As
Bspl i neCurveEl ement
Function CreateBsplineSurfaceElementl(Temp1ate
As Element, Surface As BsplineSurface) As
Bspl ineSurfaceE1 ement
Function CreateCellElementl(Name As String,
El ements ( ) As -El ement , Ori gi n As Poi nt3d,
[ IsPointCell As Bool eanl) As Cell Element
Function Createcell El ementZ(Cel1 Name As
String, Origin As Point3d, Scale As Point3d,
Truescale As Boolean, Rotation As Matrix3d) As
Cell El ement
Function CreateCe 1 El ement3(Cell Name As
String, Origin As Poi nt3d, TrueScal e As
Bool ean) As Cell E ement
Function
CreateCompl exShapeEl ementl (Chai nabl eEl ements( )
As Chai nabl eEl ement, [Fi 1 1 Mode As MsdFi 1 1 Mode =
msdFi 1 1 ModeUseActi vel) As Compl exShapeEl ement
tN Function
CreateCompl exShapeEl ementZ(Chai nabl eEl ements( )
As Chai nabl eEl ement, [Fi 1 1 Mode As MsdFi 1 1 Mode =
I The Microstation Object Model I 197

msdFi 1 l M o d e U s e A c t i v e l , [GapTol e r a n c e As D o u b l e
= -11) As Compl exShapeEl ement

B Function
CreateCompl e x S t r i n g E l e m e n t l ( C h a i n a b l e E l ements (
) As Chai n a b l e E l e m e n t ) A s Compl e x S t r i n g E l ement
Function
CreateCompl e x S t r i n g E l e m e n t Z ( C h a i n a b 1 e E l e m e n t s (
) As Chai n a b l e E l e m e n t , [GapTol e r a n c e As Doubl e
= -11) As C o m p l e x S t r i n g E l e m e n t

B F u n c t i o n CreateConeEl ementl(Temp1a t e As
E l e m e n t , BaseRadi us As Doubl e , B a s e C e n t e r P o i n t
As P o i n t 3 d , TopRadi us As Doubl e , T o p C e n t e r P o i n t
As P o i n t 3 d , R o t a t i o n A s M a t r i x 3 d ) A s
ConeEl ement
F u n c t i o n C r e a t e C o n e E l ementZ(Temp1 a t e As
E l ement , Radi us As Doubl e , B a s e C e n t e r P o i n t As
P o i n t 3 d , T o p C e n t e r P o i n t As P o i n t 3 d ) As
ConeEl ement
B F u n c t i o n CreateCrossHatchPattern(Space1 A s
D o u b l e , Space2 As D o u b l e , A n g l e 1 As D o u b l e ,
A n g l e2 As D o u b l e ) A s C r o s s H a t c h P a t t e r n
F u n c t i o n C r e a t e C u r v e E l e m e n t l ( T e m p 1 a t e As
E l e m e n t , P o i n t s 0 As P o i n t 3 d ) As C u r v e E l e m e n t
B F u n c t i o n C r e a t e D a t a b a s e L i n k ( M s 1 i n k A s Long,
E n t i t y A s Long, L i n k T y p e As M s d D a t a b a s e L i n k a g e ,
I s I n f o r m a t i o n As Boolean,
D i s p l a y a b l e A t t r i buteType As Long) As
DatabaseLink
F u n c t i o n CreateDesignFile(SeedFi1eName As
S t r i n g , NewDesignFileName As S t r i n g , Open As
Boo1 e a n ) As D e s i g n F i 1 e
B F u n c t i o n CreateDimensionEl ementl(Temp1a t e As
Element, R o t a t i o n As M a t r i x 3 d , Type As
MsdDimType, C T e x t O r i e n t a t i o n V i e w A s V i e w ] ) A s
D i m e n s i o n E l ement
F u n c t i o n CreateEllipseElementl~Template As
E l e m e n t , P e r i m e t e r P o i n t l As P o i n t 3 d ,
P e r i m e t e r p o i n t 2 As P o i n t 3 d , P e r i m e t e r P o i n t 3 As
P o i n t 3 d , C F i 11 Mode As MsdFi 11 Mode =
m s d F i l l M o d e U s e A c t i v e I ) As E l l i p s e E l e m e n t
B F u n c t i o n CreateEllipseElement2(Template A s
Element, O r i g i n As Point3d, PrimaryRadius As
198 I Chapter 11 :The Microstation Object Model - Objects I
Doubl e , S e c o n d a r y R a d i us As Doubl e , R o t a t i on As
M a t r i x 3 d , [ F i l l M o d e As M s d F i l l M o d e =
msdFi 11 ModeUseActi v e l ) As E l 1 ip s e E l ement
F u n c t i o n C r e a t e E l 1 ip t i c a l E l e m e n t l (Templ a t e As
E l e m e n t , E l 1 ip s e As E l 1 ip s e 3 d , [ F i 11 Mode As
M s d F i l l M o d e = m s d F i l l M o d e U s e A c t i v e 1 ) As
Element
F u n c t i o n CreateHatchPatternl(Space As D o u b l e ,
A n g l e As D o u b l e ) As H a t c h P a t t e r n
F u n c t i o n CreateLineElementl(Temp1ate As
E l e m e n t , V e r t i c e s ( ) As P o i n t 3 d ) As L i n e E l ement
F u n c t i o n CreateLineElementZ(Temp1ate As
E l e m e n t , S t a r t P o i n t As P o i n t 3 d , EndPoi n t As
P o i n t 3 d As L i n e E l ement
F u n c t i o n CreateObjectInMicroStation(Prog1D As
S t r i n g ) A s Unknown
F u n c t i o n C r e a t e P o i n t S t r i n g E l e m e n t l (Templ a t e As
E l e m e n t , V e r t i c e s 0 As P o i n t 3 d , D i s j o i n t As
B o o l e a n ) As P o i n t S t r i n g E l ement
F u n c t i o n C r e a t e S a v e d V i ewEl ement ( V i ewSpeci f i e r
A s V a r i a n t , Name As S t r i n g , [ D e s c r i p t i o n As
S t r i n g 1 ) A s SavedVi ewEl ement
F u n c t i o n CreateShapeElementl(Temp1ate As
E l e m e n t , V e r t i c e s ( ) As P o i n t 3 d , [ F i 11 Mode As
M s d F i l l M o d e = m s d F i l l M o d e U s e A c t i v e 1 ) As
ShapeEl ement
F u n c t i o n CreateSharedCellElementl(Name As
S t r i n g , E l e m e n t s 0 As - E l e m e n t , O r i g i n As
P o i n t 3 d , [ I s P o i n t C e l l As B o o l e a n ] ) As
SharedCell Element
F u n c t i o n CreateSharedCellElementZ~CellNameAs
S t r i n g , O r i g i n As P o i n t 3 d , S c a l e As P o i n t 3 d ,
T r u e s c a l e As B o o l e a n , R o t a t i o n As M a t r i x 3 d ) As
SharedCell Element
F u n c t i o n CreateSharedCellElement3(CellName As
S t r i n g , O r i g i n As P o i n t 3 d , T r u e S c a l e As
Bool ean) As SharedCell Element
F u n c t i o n CreateTextElementl(Temp1ate As
E l e m e n t , T e x t As S t r i n g , O r i g i n As P o i n t 3 d ,
R o t a t i o n As M a t r i x 3 d ) As T e x t E l e m e n t
I The Microstation Object Model I 199

il F u n c t i o n CreateTextNodeElementl(Temp1ate As
E l e m e n t , O r i g i n As P o i n t 3 d , R o t a t i o n As
M a t r i x 3 d ) As T e x t N o d e E l ement
il F u n c t i o n CreateTextNodeElementZ(Temp1ate As
E l e m e n t , O r i g i n As P o i n t 3 d , R o t a t i o n As
M a t r i x 3 d , [ I n c r e m e n t N o d e N u m b e r As B o o l e a n =
T r u e ] , [ R e s e r v e d As Unknown]) As
T e x t N o d e E l ement
il P r o p e r t y C u r r e n t G r a p h i c G r o u p As Long { r e a d
only}
il P r o p e r t y C u r s o r I n f o r m a t i o n As
CursorInformation {read-only}
il Function
D a t a E n t r y R e g i o n F r o m C r i t e r i a ( S t a r t P o s i t i on As
Long, L e n g t h As Long, J u s t i f i c a t i o n As
MsdData E n t r y Regi on J u s t if ic a t ion As
D a t a E n t r y Regi on
il F u n c t i o n D e g r e e s ( R a d i a n s As D o u b l e ) As D o u b l e
il Sub D e l e t e X D a t u m ( X D a t a 0 As XDatum, I n d e x As
Long)
il Sub D e t a c h c e l l L i b r a r y ( )
il F u n c t i o n DLongAbs(Va1ue As DLong) As DLong
il F u n c t i o n DLongAdd(Term1 As DLong, Term2 As
DLong) As DLong
il F u n c t i o n DLongComp(Value1 As DLong, V a l u e 2 As
DLong) As Long
il F u n c t i o n D L o n g D i v i d e ( N u m e r a t 0 r As DLong,
D e n o m i n a t o r As DLong) As DLong
il F u n c t i o n DLongFromDoubl e ( V a 1 ue As D o u b l e ) As
DLong
il F u n c t i o n DLongFromHexString(Va1ue As S t r i n g )
As DLong
il F u n c t i o n D L o n g F r o m I n t 6 4 ( V a l ue As E m p t y ) As
DLong
il F u n c t i o n DLongFromLong(Va1ue As L o n g ) As DLong
il F u n c t i o n D L o n g F r o m S t r i n g ( V a 1 u e As S t r i n g ) As
DLong
il F u n c t i o n DLongMod(Numerator As DLong,
D e n o m i n a t o r As DLong) As DLong
200 I Chapter 11 :The Microstation Object Model - Objects I
l l Function DLongMultiply(Factor1 As DLong,
Factor2 As DLong) As DLong
Function DLongNegate(Va1ue As DLong) As DLong
Function DLongSubtract(Minuend As DLong,
Subtrahend As DLong) As DLong
Function DLongToHexString(Va1ue As DLong) As
String
S u b DLongToInt64(Value As DLong)
Function DLongToLong(Va1ue As DLong) As Long
Function DLongToString(Va1ue As DLong) As
String
Function
El 1 ipse3dFromEll i pti cal El ement (El ement As
El 1 i pti cal El ement) As El 1 i pse3d
Property ExecutingVBProject As Object {read-
only1
Property Full Name As String {read-only}
Function
GetCellInformationEnumerator(IncludeSharedCel1
s As Boolean, IncludeFullPath As Boolean) As
Cell InformationEnumerator
Function GetCExpressionValue(CExpression As
String, [MdlApplicationName As String]) As
Variant
Function
GetCExpressionValueAsDLong(CExpression As
String, [MdlApplicationName As String]) As
DLong
Function GetFloodBoundary(CandidateElements0
A s -Element, Template As Element, SeedPoint A s
Point3d, [Viewspecifier As Variant],
[FindHoles As Boolean = True], [Tolerance As
Double = - 1 1 , [FillMode As MsdFillMode =
msdFi 1 1 ModeUseActi vel) As El ement
Function GetRegionDifference(RegionSolid0 As
-El ement, Regi onHol es( ) As -El ement, Templ ate

As Element, [FillMode As MsdFillMode =


msdFi 1 1 ModeUseActi vel) As El ementEnumerator
Function GetRegionIntersection(Regionl0 As
-El ement, Regi on2( ) As -El ement, Templ ate As
I The Microstation Object Model I 201

E l ement, [ F i 1 1 Mode As MsdFi 1 1 Mode =


m s d F i l l M o d e U s e A c t i v e I ) As E l e m e n t E n u m e r a t o r
il F u n c t i o n G e t R e g i o n U n i o n ( R e g i o n l ( ) As -Element,
Regi o n 2 ( ) As - E l ement, Temp1 a t e As E l ement,
[ F i l l M o d e As M s d F i l l M o d e =
m s d F i l l M o d e U s e A c t i v e I ) As E l e m e n t E n u m e r a t o r
il P r o p e r t y H a s A c t i v e D e s i g n F i l e As B o o l e a n
{ r e a d - o n 1y 1
il P r o p e r t y H a s A c t i v e M o d e l R e f e r e n c e As B o o l e a n
{ r e a d - o n 1y }
il P r o p e r t y H e i g h t As Long
il Sub I n s e r t X D a t u m ( X D a t a 0 As XDatum, I n d e x As
Long, Type As MsdXDatumType, V a l u e As V a r i a n t )
il P r o p e r t y I s A c a d e m i c V e r s i o n As B o o l e a n { r e a d -
only}
il P r o p e r t y I s C e l l L i b r a r y A t t a c h e d As Boo1 ean
{ r e a d - o n 1y }
il P r o p e r t y I s R e g i s t e r e d As B o o l e a n { r e a d - o n l y }
il P r o p e r t y I s s e r i a l i z e d As B o o l e a n { r e a d - o n l y }
il P r o p e r t y K e y i n A r g u m e n t s As S t r i n g
il P r o p e r t y L e f t P o s i t i o n As Long
il F u n c t i o n M a t r i x 3 d A d d Z S c a l e d ( M a t r i x O As
M a t r i x 3 d , M a t r i x 1 As M a t r i x 3 d , S c a l e 1 As
D o u b l e , M a t r i x 2 As M a t r i x 3 d , S c a l e 2 As D o u b l e )
As M a t r i x 3 d
il F u n c t i o n M a t r i x 3 d D e t e r m i n a n t ( M a t r i x As
M a t r i x 3 d ) As D o u b l e
il F u n c t i o n M a t r i x 3 d E q u a l ( M a t r i x l As M a t r i x 3 d ,
M a t r i x 2 As M a t r i x 3 d ) As B o o l e a n
il F u n c t i o n M a t r i x 3 d E q u a l T o l e r a n c e ( M a t r i x 1 As
M a t r i x 3 d , M a t r i x 2 As M a t r i x 3 d , T o l e r a n c e As
D o u b l e ) As B o o l e a n
il Function Matrix3dFromAxisAndRotationAngle(Axis
As Long, Radians As D o u b l e ) As M a t r i x 3 d
il Function Matrix3dFromDirectionAndScale(Vector
As P o i n t 3 d , S c a l e As D o u b l e ) As M a t r i x 3 d
il Function Matrix3dFromMatrix3dTimesMatrix3d(A
As M a t r i x 3 d , B As M a t r i x 3 d ) As M a t r i x 3 d
il Function
Matrix3dFromMatrix3dTimesMatrix3dTimesMatrix3d
202 I Chapter 11 :The Microstation Object Model - Objects I
( A As M a t r i x 3 d , B As M a t r i x 3 d , C As M a t r i x 3 d )
As M a t r i x 3 d
F u n c t i o n Matrix3dFromPoint3dColumns(XVector As
P o i n t 3 d , Y V e c t o r As P o i n t 3 d , Z V e c t o r As
P o i n t 3 d ) As M a t r i x 3 d
F u n c t i o n Matrix3dFromPoint3dRows(XVector As
P o i n t 3 d , Y V e c t o r As P o i n t 3 d , Z V e c t o r As
P o i n t 3 d ) As M a t r i x 3 d
Function
Matrix3dFromRotationBetweenVectors(VectorO As
P o i n t 3 d , V e c t o r 1 As P o i n t 3 d ) As M a t r i x 3 d
F u n c t i o n M a t r i x 3 d F r o m R o w V a l ues(XO0 As D o u b l e ,
X O 1 As D o u b l e , XO2 As D o u b l e , X10 As D o u b l e ,
X11 As D o u b l e , X12 As D o u b l e , X20 As D o u b l e ,
X21 As D o u b l e , X22 As D o u b l e ) As M a t r i x 3 d
F u n c t i o n M a t r i x 3 d F r o m S c a l e ( S c a 1 e As D o u b l e ) As
M a t r ix3d
F u n c t i o n M a t r i x 3 d F r o m S c a l e F a c t o r s ( X s c a 1 e As
D o u b l e , Y s c a l e As D o u b l e , Z s c a l e As D o u b l e ) As
M a t r ix3d
F u n c t i o n Matrix3dFromTransform3d(Transform As
T r a n s f o r m 3 d ) As M a t r i x 3 d
Function
M a t r i x 3 d F r o m V e c t o r A n d R o t a t i onAngl e ( A x i s As
P o i n t 3 d , R a d i a n s As D o u b l e ) As M a t r i x 3 d
Function
Matrix3dFromXYRotationSkewAndScal e ( X A x i s A n g 1 e
As D o u b l e , Y A x i s S k e w A n g l e As D o u b l e , X s c a l e As
D o u b l e , Y s c a l e As D o u b l e , Z s c a l e As D o u b l e ) As
M a t r ix3d
Function
Matrix3dGetComponentByRowAndColumn(Matrix As
M a t r i x 3 d , Row As Long, Col As L o n g ) As D o u b l e
F u n c t i o n Matrix3dHasInverse(Matrix As
M a t r i x 3 d ) As B o o l e a n
F u n c t i o n M a t r i x 3 d I d e n t i t y O As M a t r i x 3 d
F u n c t i o n M a t r i x 3 d I n v e r s e ( F o r w a r d As M a t r i x 3 d )
As M a t r i x 3 d
F u n c t i o n Matrix3dIsIdentity(Matrix As
M a t r i x 3 d ) As B o o l e a n
I The Microstation Object Model I 203

I4 F u n c t i o n Matrix3dIsOrthogonal(Matrix As
M a t r i x 3 d ) As B o o l e a n
I4 F u n c t i on M a t r i x3d Is R i g i d ( M a t r i x As M a t r i x 3 d )
As B o o l e a n
I4 Fun c t ion M a t r ix3d Is Rot a t e S c a 1 e Ro t a t e ( M a t r ix As
M a t r i x 3 d , R o t a t i o n 1 As M a t r i x 3 d , S c a l e F a c t o r s
As P o i n t 3 d , R o t a t i o n 2 As M a t r i x 3 d ) As B o o l e a n
I4 F u n c t i o n Matrix3dIsSignedPermutation(Matrix As
M a t r i x 3 d ) As B o o l e a n
I4 F u n c t i o n
M a t r i x 3 d I s X R o t a t i onY R o t a t i o n Z R o t a t i onScal e ( M a t
r i x As M a t r i x 3 d , RadiansX As D o u b l e , RadiansY
As D o u b l e , RadiansZ As D o u b l e , S c a l e As D o u b l e )
As B o o l e a n
I4 F u n c t i on M a t r i x 3 d I s X Y R o t a t i o n ( M a t r i x As
M a t r i x 3 d , X Y R o t a t i o n R a d i a n s As D o u b l e ) As
Boo1 ean
I4 F u n c t i o n
M a t r i x3dIsXY R o t a t i onS kewAndScal e ( M a t r i x As
M a t r i x 3 d , X A x i s A n g l e As D o u b l e , YAxisSkewAngle
As D o u b l e , X s c a l e As D o u b l e , Y s c a l e As D o u b l e ,
Z s c a l e As D o u b l e ) As B o o l e a n
I4 F u n c t i o n M a t r i x 3 d M a x A b s ( M a t r i x As M a t r i x 3 d ) As
Double
I4 F u n c t i o n M a t r i x 3 d M a x D i f f ( M a t r i x l As M a t r i x 3 d ,
M a t r i x 2 As M a t r i x 3 d ) As D o u b l e
I4 F u n c t i o n M a t r i x 3 d R o t a t i o n F r o m C o l umnZ(Norma1 As
P o i n t 3 d ) As M a t r i x 3 d
I4 F u n c t i o n
M a t r i x 3 d R o t a t i onFromPoi n t 3 d O r i g i nXY (Orig i n As
P o i n t 3 d , X P o i n t As P o i n t 3 d , Y P o i n t As P o i n t 3 d )
As M a t r i x 3 d
I4 F u n c t i o n Matrix3dRotationFromRowZ(Normal As
P o i n t 3 d ) As M a t r i x 3 d
I4 Sub Matrix3dSetComponentByRowAndColumn(Matrix
As M a t r i x 3 d , RowIndex As Long, ColumnIndex As
Long, V a l u e As D o u b l e )
I4 F u n c t i o n Matrix3dSumSquares(Matrix As
M a t r i x 3 d ) As D o u b l e
I4 F u n c t i o n Matrix3dTranspose(Matrix As M a t r i x 3 d )
As M a t r i x 3 d
204 I Chapter 11 :The Microstation Object Model - Objects I
F u n c t i o n M a t r i x 3 d Z e r o O As M a t r i x 3 d
Function
Mdl C r e a t e E l ementFromE1 e m e n t D e s c r P ( E l e m e n t D e s c r
P A s L o n g ) As E l e m e n t
Function
MdlGetDesignFileFromModel RefP(Mode1 RefP As
L o n g ) As D e s i g n F i l e
Function
MdlGetModelReferenceFromModelRefP(Mode1RefP As
Long) As ModelReference
P r o p e r t y M e s s a g e c e n t e r As M e s s a g e c e n t e r
{read-only}
P r o p e r t y Name As S t r i n g { r e a d - o n l y }
Sub OnDesignFileClosed(DesignFi1eName As
String)
Sub OnDesignFileOpened(DesignFi1eName As
String)
F u n c t i o n OpenDesignFile(DesignFi1eName As
S t r i n g , [ R e a d o n l y As B o o l e a n ] , C V 7 A c t i o n As
M s d V 7 A c t i o n = m s d V 7 A c t i o n A s k U s e r l ) As
D e s i gn F i 1 e
Function
OpenDesignFileForProgram(DesignFi1eName As
S t r i n g , [ R e a d o n l y As B o o l e a n ] ) As D e s i g n F i l e
P r o p e r t y P a t h As S t r i n g { r e a d - o n l y }
F u n c t i o n P i ( ) As D o u b l e
Function
P1 a n e 3 d I n t e r s e c t s P l a n e 3 d ( I n t e r s e c t i onRay As
Ray3d, P1 aneO As P1 ane3d, P1 a n e l As P1 a n e 3 d ) As
Boo1 ean
Function
Plane3dIntersectsRay3d(IntersectionPo n t As
P o i n t 3 d , P a r a m e t e r A s Doubl e , P1 ane A s P1 ane3d,
Ray A s Ray3d) As B o o l e a n
F u n c t i o n P o i n t Z d A d d ( P o i n t 1 As P o i n t 2 d P o i n t 2
As P o i n t 2 d ) As P o i n t 2 d
F u n c t i o n PointZdAddZScaled(0rigin As P o i n t Z d ,
V e c t o r l A s P o i n t Z d , S c a l e l As D o u b l e , V e c t o r 2
A s P o i n t 2 d , S c a l e 2 As D o u b l e ) As P o i n t 2 d
F u n c t i o n PointZdAdd3Scaled(Origin As P o i n t Z d ,
V e c t o r l As P o i n t Z d , S c a l e l As D o u b l e , V e c t o r 2
I The Microstation Object Model I 205

As P o i n t Z d , S c a l e 2 As D o u b l e , V e c t o r 3 As
P o i n t Z d , S c a l e 3 As D o u b l e ) As P o i n t 2 d
F u n c t i o n P o i n t 2 d A d d S c a l e d ( O r i g i n As P o i n t 2 d ,
V e c t o r As P o i n t 2 d , S c a l e As D o u b l e ) As P o i n t 2 d
F u n c t i o n P o i n t 2 d A r e V e c t o r s P a r a l l e l ( V e c t o r l As
P o i n t Z d , V e c t o r 2 As P o i n t 2 d ) As B o o l e a n
Function
PointZdAreVectorsPerpendicular(Vector1 As
P o i n t Z d , V e c t o r 2 As P o i n t 2 d ) As B o o l e a n
F u n c t i o n P o i n t Z d C r o s s P r o d u c t ( V e c t o r 1 As
P o i n t Z d , V e c t o r 2 As P o i n t 2 d ) As D o u b l e
F u n c t i o n P o i n t 2 d C r o s s P r o d u c t 3 P o i n t s ( O r i g i n As
P o i n t Z d , T a r g e t l As P o i n t 2 d , T a r g e t 2 As
P o i n t 2 d ) As D o u b l e
F u n c t i o n P o i n t Z d D i s t a n c e ( P o i n t 0 As P o i n t Z d ,
P o i n t l As P o i n t 2 d ) As D o u b l e
F u n c t i o n P o i n t 2 d D i s t a n c e S q u a r e d ( P o i n t l As
P o i n t Z d , P o i n t 2 As P o i n t 2 d ) As D o u b l e
F u n c t i o n P o i n t Z d D o t D i f f e r e n c e ( T a r g e t P 0 i n t As
P o i n t Z d , O r i g i n As P o i n t Z d , V e c t o r As P o i n t 2 d )
As D o u b l e
F u n c t i o n P o i n t Z d D o t P r o d u c t ( V e c t o r 1 As P o i n t 2 d ,
V e c t o r 2 As P o i n t 2 d ) As D o u b l e
F u n c t i o n P o i n t 2 d D o t P r o d u c t 3 P o i n t s ( O r i g i n As
P o i n t Z d , T a r g e t l As P o i n t Z d , T a r g e t 2 As
P o i n t 2 d ) As D o u b l e
F u n c t i o n P o i n t 2 d E q u a l ( V e c t o r l As P o i n t 2 d ,
V e c t o r 2 As P o i n t 2 d ) As B o o l e a n
F u n c t i o n P o i n t 2 d E q u a l To1 e r a n c e ( V e c t o r 1 As
P o i n t Z d , V e c t o r 2 As P o i n t Z d , T o l e r a n c e As
D o u b l e ) As B o o l e a n
F u n c t i o n P o i n t 2 d F r o m X Y ( X As D o u b l e , Y As
D o u b l e ) As P o i n t 2 d
F u n c t i o n PointZdGetComponent(Point As P o i n t Z d ,
I n d e x As L o n g ) As D o u b l e
F u n c t i o n PointZdInterpolate(Point0 As P o i n t 2 d ,
S As D o u b l e , P o i n t l As P o i n t 2 d ) As P o i n t 2 d
F u n c t i o n P o i n t Z d M a g n i t u d e ( V e c t o r As P o i n t 2 d )
As D o u b l e
206 I Chapter 11 :The Microstation Object Model - Objects I
F u n c t i o n PointZdMagnitudeSquared(Vector As
P o i n t 2 d ) As D o u b l e
F u n c t i o n P o i n t Z d M a x A b s ( V e c t o r As P o i n t 2 d ) As
Doubl e
F u n c t i o n P o i n t Z d N e g a t e ( V e c t 0 r As P o i n t 2 d ) As
Poi n t 2 d
F u n c t i o n P o i n t Z d N o r m a l i z e ( V e c t o r As P o i n t 2 d )
As P o i n t 2 d
F u n c t i o n P o i n t Z d O n e O As P o i n t 2 d
Function
Point2dSignedAngleBetweenVectors(Vectorl As
P o i n t 2 d , V e c t o r 2 As P o i n t 2 d ) As D o u b l e
F u n c t i o n P o i n t Z d S u b t r a c t ( P o i n t 1 As P o i n t Z d ,
P o i n t 2 As P o i n t 2 d ) As P o i n t 2 d
F u n c t i o n P o i n t Z d Z e r o O As P o i n t 2 d
F u n c t i o n P o i n t 3 d A d d ( P o i n t l As P o i n t 3 d , P o i n t 2
As P o i n t 3 d ) As P o i n t 3 d
F u n c t i o n Point3dAddZScaled(Origin As P o i n t 3 d ,
V e c t o r l As P o i n t 3 d , S c a l e l As D o u b l e , V e c t o r 2
As P o i n t 3 d , S c a l e 2 As D o u b l e ) As P o i n t 3 d
F u n c t i o n Point3dAddZScaledVector3d(Origin As
P o i n t 3 d , V e c t o r l As V e c t o r 3 d , S c a l e l As D o u b l e ,
V e c t o r 2 As V e c t o r 3 d , S c a l e 2 As D o u b l e ) As
Poi n t 3 d
F u n c t i o n Point3dAdd3Scaled(Origin As P o i n t 3 d ,
V e c t o r l As P o i n t 3 d , S c a l e l As D o u b l e , V e c t o r 2
As P o i n t 3 d , S c a l e 2 As D o u b l e , V e c t o r 3 As
P o i n t 3 d , S c a l e 3 As D o u b l e ) As P o i n t 3 d
F u n c t i o n Point3dAdd3ScaledVector3d(Origin As
P o i n t 3 d , V e c t o r l As V e c t o r 3 d , S c a l e l As D o u b l e ,
V e c t o r 2 As V e c t o r 3 d , S c a l e 2 As D o u b l e , V e c t o r 3
As V e c t o r 3 d , S c a l e 3 As D o u b l e ) As P o i n t 3 d
F u n c t i o n Point3dAddAngleDistance(Pointl As
P o i n t 3 d , A n g l e R a d i a n s As D o u b l e , D i s t a n c e X Y As
D o u b l e , Dz As D o u b l e ) As P o i n t 3 d
F u n c t i o n Point3dAddPoint3dVector3d(Base As
P o i n t 3 d , V e c t o r As V e c t o r 3 d ) As P o i n t 3 d
F u n c t i o n P o i n t 3 d A d d S c a l e d ( O r i g i n As P o i n t 3 d ,
V e c t o r As P o i n t 3 d , S c a l e As D o u b l e ) As P o i n t 3 d
I The Microstation Object Model I 207

F u n c t i o n P o i n t 3 d A d d S c a l e d V e c t o r 3 d ( O r i g i n As
P o i n t 3 d , V e c t o r As V e c t o r 3 d , S c a l e As D o u b l e )
As P o i n t 3 d
F u n c t i o n Point3dAngleBetweenVectors(Vectorl As
P o i n t 3 d , V e c t o r 2 As P o i n t 3 d ) As D o u b l e
Function Point3dAngleBetweenVectorsXY(Vectorl
As P o i n t 3 d , V e c t o r 2 As P o i n t 3 d ) As D o u b l e
F u n c t i o n P o i n t 3 d A r e V e c t o r s P a r a l l e l ( V e c t o r 1 As
P o i n t 3 d , V e c t o r 2 As P o i n t 3 d ) As B o o l e a n
Function
Point3dAreVectorsPerpendicular(Vectorl As
P o i n t 3 d , V e c t o r 2 As P o i n t 3 d ) As B o o l e a n
F u n c t i o n Point3dCrossProduct(Vectorl As
P o i n t 3 d , V e c t o r 2 As P o i n t 3 d ) As P o i n t 3 d
F u n c t i o n P o i n t 3 d C r o s s P r o d u c t 3 P o i n t s ( O r i g i n As
P o i n t 3 d , T a r g e t l As P o i n t 3 d , T a r g e t 2 As
P o i n t 3 d ) As P o i n t 3 d
Function Point3dCrossProduct3PointsXY(Origin
As P o i n t 3 d , T a r g e t l As P o i n t 3 d , T a r g e t 2 As
P o i n t 3 d ) As D o u b l e
F u n c t i o n P o i n t 3 d C r o s s P r o d u c t X Y ( V e c t o r l As
P o i n t 3 d , V e c t o r 2 As P o i n t 3 d ) As D o u b l e
F u n c t i o n P o i n t 3 d D i s t a n c e ( P o i n t l As P o i n t 3 d ,
P o i n t 2 As P o i n t 3 d ) As D o u b l e
F u n c t i o n P o i n t 3 d D i s t a n c e S q u a r e d ( P o i n t l As
P o i n t 3 d , P o i n t 2 As P o i n t 3 d ) As D o u b l e
F u n c t i o n P o i n t 3 d D i s t a n c e S q u a r e d X Y ( P o i n t l As
P o i n t 3 d , P o i n t 2 As P o i n t 3 d ) As D o u b l e
F u n c t i o n P o i n t 3 d D i s t a n c e X Y ( P o i n t l As P o i n t 3 d ,
P o i n t 2 As P o i n t 3 d ) As D o u b l e
F u n c t i o n P o i n t 3 d D o t D i f f e r e n c e ( T a r g e t As
P o i n t 3 d , O r i g i n As P o i n t 3 d , V e c t o r As P o i n t 3 d )
As D o u b l e
Function Point3dDotDifferenceVector3d(Target
As P o i n t 3 d , O r i g i n As P o i n t 3 d , V e c t o r As
V e c t o r 3 d ) As D o u b l e
F u n c t i o n Point3dDotProduct(Vectorl As P o i n t 3 d ,
V e c t o r 2 As P o i n t 3 d ) As D o u b l e
F u n c t i o n P o i n t 3 d D o t P r o d u c t 3 P o i n t s ( O r i g i n As
P o i n t 3 d , T a r g e t l As P o i n t 3 d , T a r g e t 2 As
P o i n t 3 d ) As D o u b l e
208 I Chapter 11 :The Microstation Object Model - Objects I
F u n c t i o n Point3dDotProduct3PointsXY(Origin As
P o i n t 3 d , T a r g e t 1 As P o i n t 3 d , T a r g e t 2 As
P o i n t 3 d ) As D o u b l e
F u n c t i o n Point3dDotProductXY(Vectorl As
P o i n t 3 d , V e c t o r 2 As P o i n t 3 d ) As D o u b l e
F u n c t i o n P o i n t 3 d E q u a l ( V e c t o r 1 As P o i n t 3 d ,
V e c t o r 2 As P o i n t 3 d ) As B o o l e a n
F u n c t i o n P o i n t 3 d E q u a l T o l e r a n c e ( V e c t o r 1 As
P o i n t 3 d , V e c t o r 2 As P o i n t 3 d , T o l e r a n c e As
Double) As Boolean
F u n c t i o n P o i n t 3 d F r o m A n g l e D i s t a n c e ( A n g 1 eRadi ans
As D o u b l e , D i s t a n c e X Y As D o u b l e , Z As D o u b l e )
As P o i n t 3 d
F u n c t i o n P o i n t 3 d F r o m M a t r i x 3 d C o l u m n ( M a t r i x As
M a t r i x 3 d , Col As Long) As P o i n t 3 d
Function
Point3dFromMatrix3dInverseTimesPoint3d(Matrix
As M a t r i x 3 d , P o i n t As P o i n t 3 d ) As P o i n t 3 d
Function
Point3dFromMatrix3dInverseTransposeTimesPoint3
d ( M a t r i x A s M a t r i x 3 d , P o i n t As P o i n t 3 d ) As
Poi n t 3 d
F u n c t i o n Point3dFromMatrix3dRow(Matrix As
M a t r i x 3 d , Row As Long) As P o i n t 3 d
Function
P o i n t 3 d FromMat r i x 3 d T i mes P o i n t 3 d ( M a t r i x As
M a t r i x 3 d , P o i n t As P o i n t 3 d ) As P o i n t 3 d
F u n c t i o n Point3dFromMatrix3dTimesXYZ(Matrix As
M a t r i x 3 d , X As D o u b l e , Y As D o u b l e , Z As
D o u b l e ) As P o i n t 3 d
Function
Point3dFromMatrix3dTransposeTimesPoint3d(Matri
x A s M a t r i x 3 d , P o i n t As P o i n t 3 d ) As P o i n t 3 d
Function
Point3dFromMatrix3dTransposeTimesXYZ(Matrix As
M a t r i x 3 d , X As D o u b l e , Y As D o u b l e , Z As
D o u b l e ) As P o i n t 3 d
F u n c t i o n Point3dFromRay3dFractionParameter(Ray
A s Ray3d, F r a c t i o n As D o u b l e ) As P o i n t 3 d
F u n c t i o n Point3dFromRay3dTangent(Ray As Ray3d)
As P o i n t 3 d
I The Microstation Object Model I 209

Function
Point3dFromSegment3dFractionParameter(Segment
As Segment3d, Fraction 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
Point3dFromTransform3dTimesXYZ(Transform As
Transform3d, X As Double, Y As Double, Z As
Double) 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, A z As Double) As Point3d
Function Point3dGetComponent(Point As Point3d,
Index As Long) As Double
Function P o i n t 3 d I n P o l y g o n X Y ( P o i n t As Point3d,
P o l y g o n V e r t i c e s O As Point3d, [Tolerance As
Double = -11) As Long
Function Point3dInterpolate(PointO As Point3d,
Fracti onparameter As Double, Poi ntl As Point3d)
As Point3d
Function Point3dIsPointInCCWSector(TestPoint
As Point3d, Origin As Point3d, Target0 As
Point3d, Targetl As Point3d, UpVector As
Point3d) As Boolean
Function
Point3dIsPointInSmallerSector(TestPoint As
Point3d, Origin As Point3d, Targetl As Point3d,
Target2 As Point3d) As Boolean
Function Point3dIsVectorInCCWSector(TestVector
As Point3d, Vector0 As Point3d, Vector1 As
Point3d, UpVector As Point3d) As Boolean
Function
Point3dIsVectorInSmallerSector(TestVector As
210 I Chapter 11 :The Microstation Object Model - Objects I
Point3d, Vector0 As Point3d, Vector1 As
Point3d) As Boolean
Function Point3dMagnitude(Vector As Point3d)
A s Double
Function Po nt3dMagnitudeSquared(Vector As
Point3d) As Double
Function Po nt3dMaxAbs(Vector As Point3d) As
Doubl e
Function Po nt3dNegate(Vector As Point3d) As
Poi nt3d
unction Point3dNormalize(Vector As Point3d) A s
Poi nt3d
Function P o i n t 3 d O n e O As Point3d
Function
Point3dPlanarAngleBetweenVectors(Vectorl As
Point3d, Vector2 As Point3d, PlaneNorma1 As
Point3d) A s Double
Function Point3dPolarAngle(Vector As Point3d)
As Double
Function Point3dProjectToPlane3d(Point As
Poi nt3d, P1 ane As P1 ane3d, CVi ewSpeci f i er As
Variant], [UseAuxiliaryCoordinateSystem As
Boolean = False]) As Point3d
Function Point3dProjectToRay3d(Parameter As
Double, Point As Point3d, Ray As Ray3d,
[Viewspecifier As Variant],
[UseAuxiliaryCoordinateSystem As Boolean =
False]) As Point3d
Function Point3dRotateXY(Vector As Point3d,
Theta A s Double) As Point3d
Function Point3dScale(Vector As Point3d, Scale
As Double) As Point3d
S u b Point3dSetComponent(Point As Point3d,
Index A s Long, Value As Double)
Function
Point3dSignedAngleBetweenVectors(Vectorl As
Point3d, Vector2 As Point3d, Orientationvector
As Point3d) As Double
Function
Point3dSmallerAngleBetweenUnorientedVectors~Ve
ctorl A s Point3d, Vector2 A s Point3d) As Double
I The Microstation Object Model I 21 1

Function
Point3dSmallerAngleBetweenUnorientedVectorsXY~
V e c t o r 1 As P o i n t 3 d , V e c t o r 2 As P o i n t 3 d ) As
Double
F u n c t i o n P o i n t 3 d S u b t r a c t ( P o i n t l As P o i n t 3 d ,
P o i n t 2 As P o i n t 3 d ) As P o i n t 3 d
Function Point3dSubtractPoint3dVector3d(Base
As P o i n t 3 d , V e c t o r As V e c t o r 3 d ) As P o i n t 3 d
F u n c t i o n P o i n t 3 d r i p l e P r o d u c t ( V e c t o r 1 As
P o i n t 3 d , V e c t o r 2 As P o i n t 3 d , V e c t o r 3 As
P o i n t 3 d ) As Doub e
F u n c t i on P o i n t 3 d r i p l e P r o d u c t 4 P o i n t s (Orig i n As
P o i n t 3 d , T a r g e t 1 As P o i n t 3 d , T a r g e t 2 As
P o i n t 3 d , T a r g e t 3 As P o i n t 3 d ) As D o u b l e
F u n c t i o n P o i n t 3 d Z e r o ( ) As P o i n t 3 d
F u n c t i o n P o i n t s T o P i x e l s X ( P o i n t C o o r d i n a t e As
D o u b l e ) As Long
F u n c t i o n P o i n t s T o P i x e l s Y ( P o i n t C o o r d i n a t e As
D o u b l e ) As Long
P r o p e r t y P r o c e s s I D As Long {read-only}
Sub Q u i t 0
F u n c t i o n R a d i a n s ( D e g r e e s As D o u b l e ) As D o u b l e
F u n c t i o n R a n g e 3 d C o n t a i n s P o i n t 3 d ( R a n g e As
Range3d, P o i n t As P o i n t 3 d ) As B o o l e a n
F u n c t i o n Range3dContainsXYZ(Range As Range3d,
X As D o u b l e , Y As D o u b l e , Z As D o u b l e ) As
Boo1 ean
F u n c t i o n Range3dEqual ( R a n g e l As Range3d,
Range2 As Range3d) As B o o l e a n
F u n c t i o n Range3dEqual To1 e r a n c e ( Range0 As
Range3d, R a n g e l As Range3d, T o l e r a n c e As
D o u b l e ) As B o o l e a n
F u n c t i o n Range3dExtentSquared(Range As
Range3d) As D o u b l e
F u n c t i o n R a n g e 3 d F r o m P o i n t 3 d ( P o i n t As P o i n t 3 d )
As Range3d
F u n c t i o n R a n g e 3 d F r o m P o i n t 3 d P o i n t 3 d ( P o i n t O As
P o i n t 3 d , P o i n t 1 As P o i n t 3 d ) As Range3d
Function
R a n g e 3 d F r o m P o i n t 3 d P o i n t 3 d P o i n t 3 d ( P o i n t O As
212 I Chapter 11 :The Microstation Object Model - Objects I
P o i n t 3 d , P o i n t 1 As P o i n t 3 d , P o i n t 2 As P o i n t 3 d )
As Range3d
F u n c t i o n Range3dFromRange3dMargi n (Range As
Range3d, M a r g i n As D o u b l e ) As Range3d
F u n c t i o n Range3dFromXYZ(X As D o u b l e , Y As
D o u b l e , Z As D o u b l e ) As Range3d
F u n c t i o n Range3dFromXYZXYZ(Xl As D o u b l e , Y 1 As
D o u b l e , Z 1 As D o u b l e , X2 As D o u b l e , Y2 As
D o u b l e , 22 As D o u b l e ) As Range3d
F u n c t i o n R a n g e 3 d I n i t O As Range3d
F u n c t i o n R a n g e 3 d I n t e r s e c t ( R a n g e l As Range3d,
Range2 A s Range3d) As Range3d
F u n c t i o n R a n g e 3 d I n t e r s e c t 2 ( Resul t R a n g e As
Range3d, R a n g e l As Range3d, Range2 As Range3d)
As B o o l e a n
Function
Range3dIsContainedInRange3d(InnerRange As
Range3d, O u t e r R a n g e As Range3d) As B o o l e a n
F u n c t i o n R a n g e 3 d I s N u l l (Range As Range3d) As
Boo1 ean
F u n c t i o n Range3dScaleAboutCenter(RangeIn As
Range3d, S c a l e As D o u b l e ) As Range3d
F u n c t i o n Range3dUni on (Range0 As Range3d,
R a n g e l As Range3d) As Range3d
F u n c t i o n Range3dUnionPoint3d(Range As Range3d,
P o i n t A s P o i n t 3 d ) As Range3d
F u n c t i o n Range3dUni onXY Z ( Range As Range3d, X As
D o u b l e , Y As D o u b l e , Z As D o u b l e ) As Range3d
P r o p e r t y R a s t e r M a n a g e r As R a s t e r M a n a g e r
{read-only}
Sub Ray3dC1 o s e s t P o i n t (Ray As Ray3d, S p a c e P o i n t
As P o i n t 3 d , C1 o s e P o i n t As P o i n t 3 d ,
C1 o s e F r a c t i o n As D o u b l e )
Sub Ray3dC1 o s e s t P o i n t B o u n d e d ( Ray As Ray3d,
S p a c e P o i n t As P o i n t 3 d , C1 o s e P o i n t As P o i n t 3 d ,
C1 o s e F r a c t i o n As D o u b l e )
Sub Ray3dC1 o s e s t P o i ntBoundedXY (Ray As Ray3d,
S p a c e P o i n t As P o i n t 3 d , C1 o s e P o i n t As P o i n t 3 d ,
C1 o s e F r a c t i o n As D o u b l e )
I The Microstation Object Model I 213

Sub Ray3dC1 o s e s t P o i n t X Y (Ray As Ray3d,


S p a c e P o i n t As P o i n t 3 d , C l o s e P o i n t As P o i n t 3 d ,
C1 o s e F r a c t i on As Doubl e )
F u n c t i o n Ray3dFromPoint3dStartEnd(PointO As
P o i n t 3 d , P o i n t l As P o i n t 3 d ) As Ray3d
F u n c t i o n Ray3dFromPoint3dStartTangent(PointO
As P o i n t 3 d , T a n g e n t As P o i n t 3 d ) As Ray3d
F u n c t i o n Ray3dFromSegment3d(Segment As
Segment3d) As Ray3d
Function
Ray3dFromTransform3dTimesRay3d(Transform As
T r a n s f o r m 3 d , Ray As Ray3d) As Ray3d
F u n c t i o n Ray3dFromXYZXYZStartEnd(XO As D o u b l e ,
Y O As D o u b l e , ZO As D o u b l e , X 1 As D o u b l e , Y 1 As
D o u b l e , Z1 As D o u b l e ) As Ray3d
F u n c t i o n R a y 3 d L e n g t h ( R a y As Ray3d) As D o u b l e
F u n c t i o n R a y 3 d L e n g t h S q u a r e d ( R a y As Ray3d) As
Double
F u n c t i o n Ray3dP1 a n e 3 d I n t e r s e c t ( Ray As Ray3d,
P l a n e As P l a n e 3 d , P o i n t As P o i n t 3 d , F r a c t i o n As
D o u b l e ) As B o o l e a n
F u n c t i o n Ray3dRay3dCl o s e s t A p p r o a c h ( Ray0 As
Ray3d, R a y l As Ray3d, P o i n t O As P o i n t 3 d ,
F r a c t i o n 0 As D o u b l e , P o i n t l As P o i n t 3 d ,
F r a c t i o n 1 As D o u b l e ) As B o o l e a n
F u n c t i o n R a y 3 d R a y 3 d I n t e r s e c t X Y (Ray0 As Ray3d,
R a y l As Ray3d, P o i n t O As P o i n t 3 d , F r a c t i o n 0 As
D o u b l e , P o i n t l As P o i n t 3 d , F r a c t i o n l As D o u b l e )
As B o o l e a n
Sub RedrawAllViews([DrawMode As MsdDrawingMode
= msdDrawi ngModeNormal1)

Sub R e g i s t e r V 8 T o V 7 F i l t e r ( H a n d 1 e r As
IConvertV8ToV7)
Sub R e m o v e A t t a c h m e n t E v e n t s H a n d l e r ( E v e n t H a n d 1 e r
As I A t t a c h m e n t E v e n t s )
Sub
R e m o v e C h a n g e T r a c k E v e n t s H a n d l e r ( E v e n t H a n d e r As
IChangeTrackEvents)
Sub
R e m o v e L e v e l C h a n g e E v e n t s H a n d l e r ( E v e n t H a n d e r As
IL e v e l C h a n g e E v e n t s )
214 I Chapter 11:The Microstation Object Model - Objects I
Sub
RemoveModalDialogEventsHandler(EventHand1er As
IModal Dial ogEvents)
Sub
RemoveModelActivateEventsHandler(EventHand1er
As IModel Acti vateEvents)
Sub
RemoveModelChangeEventsHandler(EventHand1er As
IModel ChangeEvents)
Sub RemoveSaveAsEventsHandler(EventsHand1er As
ISaveAsEvents)
Sub RemoveViewUpdateEventsHandler(EventHand1er
As IViewUpdateEvents)
Sub ResetDisplaySet(Sh0wEverything As Boolean)
Sub Savesettingso
Sub Segment3dClosestPoint(Segment As
Segment3d, SpacePoi nt As Poi nt3d, C1 osePoi nt As
Point3d, C1 oseFracti on As Doubl e)
Sub Segment3dClosestPointBounded(Segment As
Segment3d, SpacePoi nt As Poi nt3d, C1 osePoi nt As
Point3d, C1 oseFracti on As Doubl e)
Sub Segment3dClosestPointBoundedXY(Segment As
Segment3d, SpacePoi nt As Poi nt3d, C1 osePoi nt As
Point3d, C1 oseFracti on As Doubl e)
Sub Segment3dClosestPointXY(Segment As
Segment3d, SpacePoi nt As Poi nt3d, C1 osePoi nt As
Point3d, C1 oseFracti on As Doubl e)
Function Segment3dFromPoint3dStartEnd(PointO
As Point3d, Point1 As Point3d) As Segment3d
Function
Segment3dFromPoint3dStartTangent(PointO As
Point3d, Tangent As Point3d) As Segment3d
Function Segment3dFromRay3d( Ray As Ray3d) As
Segment3d
Function
Segment3dFromTransform3dTimesSegment3d(Transfo
rm As Transform3d, Segment As Segment3d) As
Segment3d
Function Segment3dFromXYZXYZStartEnd(XO As
Double, Y O As Double, ZO As Double, X 1 As
I The Microstation Object Model I 21 5

Double, Y 1 As Double, Z1 As Double) As


Segment3d
I4 Function Segment3dLength(Segment A s Segment3d)
As Double
I4 Function Segment3dLengthSquared(Segment As
Segment3d) As Doubl e
I4 Function Segment3dPlane3dIntersect(Segment A s
Segment3d, Plane A s Plane3d, Point As Point3d,
Fraction As Double) A s Boolean
I4 Function
Segment3dSegment3dC1osestApproach(SegmentO As
Segment3d, Segmentl As Segment3d, PointO As
Point3d, Fraction0 As Double, Pointl As
Point3d, Fractionl As Double) As Boolean
I4 Function
Segment3dSegment3dIntersectXY(SegmentO A s
Segment3d, Segmentl A s Segment3d, PointO A s
Point3d, Fraction0 A s Double, Pointl A s
Point3d, Fraction1 A s Double) A s Boolean
I4 Sub SetCExpressionValue(CExpression As String,
NewVal ue As Variant, [Mdl Appl i cationName As
Stri ngl)
I4 Sub SetCExpressionValueAsDLong(CExpression A s
String, NewValue As DLong, CMdlApplicationName
As String])
I4 Sub ShowCommand([Command As String])
I4 Sub ShowError([Error A s String])
I4 Sub ShowPrompt([Prompt As String])
I4 Sub ShowStatus([Status A s String])
I4 Sub ShowTempMessage(Area As MsdStatusBarArea,
Message As String, [Details As String])
I4 Property S t a n d a r d s C h e c k e r C o n t r o l l e r A s
StandardsCheckerController {read-only}
I4 Sub S t a r t B u s y C u r s o r O
I4 Sub S t o p B u s y C u r s o r O
I4 Property TopPosition As Long
I4 Function Transform3dEqual(Transforml A s
Transform3d, Transform2 A s Transform3d) A s
Boo1 ean
216 I Chapter 11 :The Microstation Object Model - Objects I
Function Transform3dEqualTolerance(Transforml
As Transform3d, Transform2 As Transform3d,
MatrixTol erance As Doubl e , Poi ntTol erance As
Double) As Boolean
Function Transform3dFactorMirror(Transform As
Transform3d, ResidualTransform As Transform3d,
MirrorTransform As Transform3d, Fixedpoint As
Point3d, P1 aneNormal As Poi nt3d) As Boo1 ean
Function
Transform3dFromLi neAndRotati onAngl e( Poi ntO As
Point3d, Point1 As Point3d, Radians As Double)
As Transform3d
Function Transform3dFromMatrix3d(Matrix As
Matrix3d) As Transform3d
Function
Transform3dFromMatrix3dAndFixedPoint3d(Matrix
As Matrix3d, Origin As Point3d) As Transform3d
Function Transform3dFromMatrix3dPoint3d(Matrix
As Matrix3d, Translation As Point3d) As
Transform3d
Function
Transform3dFromMatrix3dTimesTransform3d(Matrix
As Matrix3d, Transform As Transform3d) As
Transform3d
Function Transform3dFromMi rrorPl ane(0rigin As
Point3d, Normal As Point3d) As Transform3d
Function Transform3dFromPl ane3dToWorl d( P1 ane
As Plane3d) As Transform3d
Function Transform3dFromPoi nt3d(Transl ati on As
Point3d) As Transform3d
Function Transform3dFromRowValues(XOO As
Double, X O 1 As Double, X O 2 As Double, T x As
Double, X10 As Double, X11 As Double, X12 As
Double, Ty As Double, X20 As Double, X21 As
Double, X 2 2 As Double, Tz As Double) As
Transform3d
Function
Transform3dFromSquaredTransform3d(Transform As
Transform3d, PrimaryAxis As Long,
SecondaryAxis As Long) As Transform3d
Function
Transform3dFromTransform3dTimesMatrix3d(Transf
I The Microstation Object Model I 21 7

orm As Transform3d, Matrix As Matrix3d) As


Transform3d
Function
Transform3dFromTransform3dTimesTransform3d(Tra
nsforml As Transform3d, Transform2 A s
Transform3d) A s Transform3d
Function
Transform3dFromTransform3dTimesTransform3dTime
sTransform3d(Transforml As Transform3d,
Transform2 As Transform3d, Transform3 As
Transform3d) As Transform3d
Function Transform3dFromWorl dToPl ane3d( P1 ane
As Plane3d) As Transform3d
Function Transform3dFromXYZ(X As Double Y As
Double, Z As Double) As Transform3d
Function
Transform3dGetMatrixComponentByRowAndCo umn (Tr
ansform As Transform3d, R o w A s Long, Co A s
Long) As Double
Function
Transform3dGetPointComponent(Transform As
Transform3d, R o w As Long) As Double
Function Transform3dHasInverse(Transform A s
Transform3d) A s Boolean
Function T r a n s f o r m 3 d I d e n t i t y O As Transform3d
Function Transform3dInverse(In A s Transform3d)
As Transform3d
Function Transform3dIsIdentity(Transform As
Transform3d) As Boolean
Function
Transform3dIsMirrorAboutPlane(Transform As
Transform3d, PlanePoint A s Point3d,
P1 aneNormal As Poi nt3d) A s Boo1 ean
i
l Function Transform3dIsPlanar(Transform As
Transform3d, Normal As Point3d) As Boolean
Function Transform3dIsRigid(Transform A s
Transform3d) A s Boolean
Function
Transform3dIsRotateAroundLine(Transform As
Transform3d, FixedPoint As Point3d,
218 I Chapter 11 :The Microstation Object Model - Objects I
D i r e c t i o n v e c t o r As P o i n t 3 d , R a d i a n s As Doubl e )
As B o o l e a n
F u n c t i o n Transform3dIsTranslate(Transform As
Transform3d, T r a n s l a t i o n As P o i n t 3 d ) As Boolean
Function
T r a n s f orm3d Is T r a n s 1 a t e R o t a t eSca 1 e R o t a t e ( T r a n s f
orm As T r a n s f o r m 3 d , T r a n s l a t i o n As P o i n t 3 d ,
R o t a t i o n 1 As M a t r i x 3 d , S c a l e F a c t o r s As P o i n t 3 d ,
R o t a t i o n 2 As M a t r i x 3 d ) As B o o l e a n
F u n c t i o n Transform3dIsUniformScale(Transform
A s T r a n s f o r m 3 d , F i x e d p o i n t A s P o i n t 3 d , S c a l e As
Double) As Boolean
Function
Transform3dIsUniformScaleAndRotateAroundLine~T
r a n s f o r m As T r a n s f o r m 3 d t F i x e d P o i n t As P o i n t 3 d ,
D i r e c t i o n v e c t o r As P o i n t 3 d , R a d i a n s As Doubl e ,
S c a l e As D o u b l e ) As B o o l e a n
Sub
Transform3dSetMatrixComponentByRowAndColumn~Tr
a n s f o r m A s T r a n s f o r m 3 d , RowIndex As Long,
C o l u m n I n d e x As Long, V a l u e As D o u b l e )
Sub Transform3dSetPointComponent(Transform As
T r a n s f o r m 3 d , RowIndex As Long, V a l u e As D o u b l e )
F u n c t i o n T r a n s f o r m 3 d Z e r o O As T r a n s f o r m 3 d
F u n c t i o n U p d a t e G r a p h i c G r o u p N u m b e r O As Long
P r o p e r t y UserName As S t r i n g {read-only}
P r o p e r t y V B E As O b j e c t {read-only}
F u n c t i o n V e c t o r 3 d A d d ( V e c t o r l As V e c t o r 3 d ,
V e c t o r 2 A s V e c t o r 3 d ) As V e c t o r 3 d
F u n c t i o n V e c t o r 3 d A d d Z S c a l e d ( 0 r i g i n As
V e c t o r 3 d , V e c t o r l As V e c t o r 3 d , S c a l e l As
D o u b l e , V e c t o r 2 As V e c t o r 3 d , S c a l e 2 As D o u b l e )
As V e c t o r 3 d
F u n c t i o n V e c t o r 3 d A d d 3 S c a l e d ( 0 r i g i n As
V e c t o r 3 d , V e c t o r l As V e c t o r 3 d , S c a l e l As
D o u b l e , V e c t o r 2 As V e c t o r 3 d , S c a l e 2 A s D o u b l e ,
V e c t o r 3 A s V e c t o r 3 d , S c a l e 3 As D o u b l e ) As
Vector3d
F u n c t i o n Vector3dAddScaled(Origin As V e c t o r 3 d ,
V e c t o r As V e c t o r 3 d , S c a l e As D o u b l e ) As
Vector3d
I The Microstation Object Model I 21 9

Function Vector3dAngleBetweenVectors(Vectorl
As V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As D o u b l e
Function Vector3dAngleBetweenVectorsXY(Vectorl
As V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As D o u b l e
F u n c t i o n Vector3dAreVectorsParall e l ( V e c t o r 1 As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As B o o l e a n
Function
Vector3dAreVectorsPerpendicular(Vectorl As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As B o o l e a n
F u n c t i o n V e c t o r 3 d C r o s s P r o d u c t ( V e c t o r l As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As V e c t o r 3 d
F u n c t i o n V e c t o r 3 d C r o s s P r o d u c t 3 P o i n t s ( O r i g i n As
P o i n t 3 d , T a r g e t 1 As P o i n t 3 d , T a r g e t 2 As
P o i n t 3 d ) As V e c t o r 3 d
F u n c t i o n V e c t o r 3 d C r o s s P r o d u c t X Y ( V e c t o r l As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As D o u b l e
F u n c t i o n Vector3dDistance(Vectorl As V e c t o r 3 d ,
V e c t o r 2 As V e c t o r 3 d ) As D o u b l e
F u n c t i o n V e c t o r 3 d D i s t a n c e S q u a r e d ( V e c t o r l As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As D o u b l e
F u n c t i o n V e c t o r 3 d D i s t a n c e S q u a r e d X Y ( V e c t o r l As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As D o u b l e
F u n c t i o n V e c t o r 3 d D i s t a n c e X Y ( V e c t o r l As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As D o u b l e
F u n c t i o n V e c t o r 3 d D o t P r o d u c t ( V e c t o r l As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As D o u b l e
F u n c t i o n V e c t o r 3 d D o t P r o d u c t X Y ( V e c t o r l As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As D o u b l e
F u n c t i o n V e c t o r 3 d D o t P r o d u c t X Y Z ( V e c t o r As
V e c t o r 3 d , Ax As D o u b l e , Ay As D o u b l e , Az As
D o u b l e ) As D o u b l e
F u n c t i o n V e c t o r 3 d E q u a l ( V e c t o r l As V e c t o r 3 d ,
V e c t o r 2 As V e c t o r 3 d ) As B o o l e a n
F u n c t i o n V e c t o r 3 d E q u a l T o l e r a n c e ( V e c t o r l As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d , T o l e r a n c e As
D o u b l e ) As B o o l e a n
F u n c t i o n V e c t o r 3 d F r o m M a t r i x 3 d C o l u m n ( M a t r i x As
M a t r i x 3 d , Col As L o n g ) As V e c t o r 3 d
F u n c t i o n V e c t o r 3 d F r o m M a t r i x 3 d R o w ( M a t r i x As
M a t r i x 3 d , Row As L o n g ) As V e c t o r 3 d
220 I Chapter 11 :The Microstation Object Model - Objects I
Function
Vector3dFromMatrix3dTimesVector3d(Matrix As
Matrix3d, Vector As Vector3d) As Vector3d
Function Vector3dFromMatrix3dTimesXYZ(Matrix
A s Matrix3d, X As Double, Y As Double, Z As
Double) A s Vector3d
Function
Vector3dFromMatrix3dTransposeTimesVector3d~Mat
rix As Matrix3d, Vector As Vector3d) As
Vector3d
Function
Vector3dFromMatrix3dTransposeTimesXYZ(Matrix
A s Matrix3d, X As Double, Y As Double, Z As
Double) A s Vector3d
Function Vector3dFromPoint3d(Point As Point3d)
As Vector3d
Function
Vector3dFromTransform3dColumn(Transform As
Transform3d, Col As Long) As Vector3d
Function Vector3dFromTransform3dRow(Transform
As Transform3d, Row As Long) As Vector3d
Function
Vector3dFromTransform3dTimesVector3d(Transform
A s Transform3d, Vector As Vector3d) As Vector3d
Function
Vector3dFromTransform3dTimesXYZ(Transform As
Transform3d, X As Double, Y As Double, Z As
Double) As Vector3d
Function
Vector3dFromTransform3dTranslation(Transform
A s Transform3d) As Vector3d
Function
Vector3dFromTransform3dTransposeTimesVector3d~
Transform As Transform3d, Vector As Vector3d)
As Vector3d
Function
Vector3dFromTransform3dTransposeTimesXYZ~Trans
form As Transform3d, X As Double, Y A s Double,
Z A s Double) As Vector3d
Function Vector3dFromXY(Ax As Double, Ay As
Double) As Vector3d
I The Microstation Object Model I 221

Function V e c t o r 3 d F r o m X Y A n g l e A n d M a g n i t u d e ( T h e t a
As Double, Magnitude As Double) As Vector3d
Function Vector3dFromXYZ(Ax As Double, Ay As
Double, Az As Double) As Vector3d
Function Vector3dGetComponent(Vector As
Vector3d, Index As Long) As Double
Function Vector3dInterpolate(VectorO As
Vector3d, Fractionparameter As Double, Vectorl
As Vector3d) As Vector3d
Function
Vector3dIsVectorInCCWSector(TestVector As
Vector3d, Vector0 As Vector3d, Vectorl As
Vector3d, UpVector As Vector3d) As Boolean
Function
Vector3dIsVectorInCCWXYSector(TestVector As
Vector3d, Vector0 As Vector3d, Vectorl As
Vector3d) As Bool ean
Function
Vector3dIsVectorInSmallerSector(TestVector As
Vector3d, Vector0 As Vector3d, Vectorl As
Vector3d) As Bool ean
Function Vector3dMagnitude(Vector As Vector3d)
As Double
Function Vector3dMagnitudeSquared(Vector As
Vector3d) As Double
Function Vector3dMagnitudeSquaredXY(Vector As
Vector3d) As Double
Function Vector3dMagnitudeXY(Vector As
Vector3d) As Double
Function Vector3dMaxAbs(Vector As Vector3d) As
Double
Function Vector3dMaxAbsDifference(Vectorl As
Vector3d, Vector2 As Vector3d) As Double
Function Vector3dNegate(Vector As Vector3d) As
Vector3d
Function Vector3dNormalize(Vector As Vector3d)
As Vector3d
Function Vector3dOneO As Vector3d
Function
Vector3dPlanarAngleBetweenVectors(Vectorl As
222 I Chapter 11:The Microstation Object Model - Objects I
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d , PlaneNorma1 As
V e c t o r 3 d ) As D o u b l e
F u n c t i o n V e c t o r 3 d P o l a r A n g l e ( V e c t o r As
V e c t o r 3 d ) As D o u b l e
F u n c t i o n V e c t o r 3 d R o t a t e X Y ( V e c t o r As V e c t o r 3 d ,
T h e t a As D o u b l e ) As V e c t o r 3 d
El F u n c t i o n V e c t o r 3 d S c a l e ( V e c t o r As V e c t o r 3 d ,
S c a l e As D o u b l e ) As V e c t o r 3 d
Function
Vector3dSignedAngleBetweenVectors(Vectorl As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ,
O r i e n t a t i o n v e c t o r As V e c t o r 3 d ) As D o u b l e
Function
Vector3dSmallerAngleBetweenUnorientedVectors~V
e c t o r l As V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As
Doubl e
Function
Vector3dSmallerAngleBetweenUnorientedVectorsXY
( V e c t o r 1 As V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d ) As
Doubl e
F u n c t i o n Vector3dSubtract(Vectorl As V e c t o r 3 d ,
V e c t o r 2 As V e c t o r 3 d ) As V e c t o r 3 d
F u n c t i o n Vector3dSubtractPoint3dPoint3d(Target
As P o i n t 3 d , Base As P o i n t 3 d ) As V e c t o r 3 d
F u n c t i o n Vector3dTripleProduct(Vectorl As
V e c t o r 3 d , V e c t o r 2 As V e c t o r 3 d , V e c t o r 3 As
V e c t o r 3 d ) As D o u b l e
F u n c t i o n Vector3dUnitPerpendicularXY(Vector As
V e c t o r 3 d ) As V e c t o r 3 d
F u n c t i o n V e c t o r 3 d Z e r o O As V e c t o r 3 d
P r o p e r t y V e r s i o n As S t r i n g { r e a d - o n l y }
P r o p e r t y V i s i b l e As B o o l e a n
P r o p e r t y W i d t h As Long

ApplicationObjectConnector
P r o p e r t y A p p l ic a t i on As A p p l ic a t i on { r e a d -
only1

Attachment
Sub A c t i v a t e 0
I The Microstation Object Model I 223

il Sub AddEl ement( El ement As El ement


il Sub AddElements(Elements0 As -Element)
il Function AddNewNamedGroup([Name As String],
[Description As String]) As NamedGroupElement
il Sub AddUserAttributeData(Attribute1D As Long,
Attri buteData As DataBl ock)
il Property AnyEl ementsSel ected As Bool ean
{ read-on1y 1
il Property AsAttachment As Attachment {read-
only}
il Property Attachmentorigin As Point3d {read
only}
il Property Attachments As Attachments {read-
only}
il Property AttachName As String {read-only)
il Property CanBePl acedAsCel1 As Bool ean
il Property Cell Type As MsdCel 1 Type
il Property ControlElementCache As Elementcache
{ read-on1y }
il Function C o p y 0 As Attachment
il Function CopyEl ement( El ement As El ement,
CCopyContext As CopyContextl) As Element
il Sub Del eteAl1 XData (
il Function DeleteUserAttributeData(Attribute1D
As Long, Index As Integer) As Integer
il Sub DeleteXData(App1icationName As String)
il Property Description As String
il Property DesignFile As DesignFile {read-only}
il Property Di spl ayAsNested As Bool ean
il Property DisplayFlag As Boolean
il Property Di spl ayPriori ty As Long
il Property Di spl aysRasterReferences As Bool ean
il Function D o u b l e T o W o r k i n g U n i t s ( V a 1 u e As Double)
As String
il Function
El ementCacheContainingFi1 ePosi tion( Fil ePosi tio
n As Long, CCacheIndex As Long]) As
El ementcache
224 I Chapter 11 :The Microstation Object Model - Objects I
Property ElementID As DLong {read-only}
Property El ementsLocatab1 e As Bool ean
Property El ementssnappabl e As Bool ean
Property El ementsVi si bl e As Bool ean
Function GetElementByID(Element1D As DLong) As
Element
Function GetElementByID64(ElementID64 As
Empty) As Element
Function GetLastValidGraphical E l e m e n t 0 As
Element
Function GetMasterToReferenceTransformO As
Transform3d
Function GetNamedGroup(Gr0upName As String) As
NamedGroupEl ement
Function GetReferenceToMasterTransformO As
Transform3d
Function G e t S e l ectedElementsO As
El ement Enumerator
Function G e t S h e etDefinitionO As
SheetDefinition
Function GetUserAttributeData(Attribute1D As
Long) As DataBl ock()
Function GetXData(App1icationName As String)
As X D a t u m O
Function GetXDataApplicationNamesO As
String( (
Property G1 obal Li neStyl eScal e As
MsdGl obal LineStyl eScal e
Property G1 obal Ori gi n As Poi nt3d {read-only}
Property Graphical El ementcache As El ementcache
{read-only}
Function H a s A n y X D a t a O As Boolean
Function HasXData(App1icationName As String)
As Boolean
Property Is3D As Boolean {read-only}
Property IsActive As Boolean {read-only}
Property IsAttachment As Boolean {read-only}
Property IsEl ementSel ected As Bool ean {read-
only}
I The Microstation Object Model I 225

P r o p e r t y I s L o c k e d As B o o l e a n
P r o p e r t y I s M i s s i n g F i l e As B o o l e a n {read-only}
P r o p e r t y I s M i s s i n g M o d e l As B o o l e a n {read-
only}
P r o p e r t y I s R e a d O n l y As B o o l ean {read-only}
P r o p e r t y I s T r u e S c a l e As B o o l e a n {read-only}
P r o p e r t y L e v e l As L e v e l
P r o p e r t y L e v e l s As L e v e l s {read-only}
P r o p e r t y L i n e S t y l e s S c a l ed As B o o l ean
P r o p e r t y L o g i c a l D e s c r i p t i o n As S t r i n g
P r o p e r t y L o g i c a l N a m e As S t r i n g
P r o p e r t y M a n i p u l a t e A s E l ement As B o o l ean
P r o p e r t y M a s t e r o r i g i n As P o i n t 3 d {read-only}
P r o p e r t y M a s t e r u n i t As M e a s u r e m e n t u n i t
F u n c t i o n MdlModel R e f P ( ) As Long
Sub M o v e ( 0 f f s e t As P o i n t 3 d , A p p l y T o C l i p E l e m e n t
As B o o l e a n )
P r o p e r t y Name As S t r i n g
P r o p e r t y NamedGroup As S t r i n g
P r o p e r t y N e s t L e v e l As Long
P r o p e r t y N e s t o v e r r i d e s As M s d N e s t O v e r r i d e s
P r o p e r t y NewLevel D i s p l ay As MsdNewLevel D i s p l ay
P r o p e r t y P a r e n t M o d e l R e f e r e n c e As
Model R e f e r e n c e {read-only}
P r o p e r t y P l o t 3 d As B o o l e a n
P r o p e r t y P r e s e n t a t i o n As MsdRenderingMode
P r o p e r t y P r i n t C o l o r A d j u s t m e n t As B o o l e a n
Sub PropagateAnnotationScaleO
F u n c t i o n Range( I n c l u d e A t t a c h m e n t s As B o o l e a n )
As Range3d
F u n c t i o n R e a t t a c h ( F i 1 e N a m e As S t r i n g ,
ModelName As S t r i n g ) As A t t a c h m e n t
Sub Redraw(CDrawMode As MsdDrawingMode =
msdDrawi ngModeNormal1)
Sub RemoveEl e m e n t ( E l ement As E l ement
Sub Rep1 a c e E l e m e n t ( 0 l d E l ement As E l e m e n t ,
NewEl ement As E l e m e n t )
226 I Chapter 11:The Microstation Object Model - Objects I
El P r o p e r t y R e v i s i onNumber As S t r i n g
El Sub R e w r i t e 0
Sub R o t a t e ( P i v o t As P o i n t 3 d , AboutX As D o u b l e ,
AboutY As D o u b l e , A b o u t Z As D o u b l e ,
V i e w s p e c i f i e r As V a r i a n t )
El P r o p e r t y R o t a t i o n As M a t r i x 3 d { r e a d - o n l y }
El P r o p e r t y S c a l e F a c t o r As D o u b l e
El P r o p e r t y S c a l e M a s t e r U n i t s As Doubl e { r e a d -
only1
Sub S c a l e U n i f o r m ( 0 r i g i n As P o i n t 3 d ,
S c a l e F a c t o r As Doubl e , A p p l y T o C l ip E l ement As
B o o l ean
El F u n c t i o n Scan( [ S c a n C r i t e r i a As
E l e m e n t S c a n C r i t e r i a l ) As E l e m e n t E n u m e r a t o r
Sub S e l e c t E l ement ( E l ement As E l e m e n t ,
[ D i s p l ayAsSel e c t e d As B o o l ean = T r u e ] )
El Sub S e t A t t a c h N a m e D e f e r r e d ( F i 1 e S p e c i f i c a t i on As
String)
El Sub S e t S h e e t D e f i n i t i o n ( N e w D e f i n i t i 0 n As
SheetDefinition)
El Sub SetXData(App1icationName As S t r i n g ,
NewXDataO As XDatum)
P r o p e r t y S t o r a g e u n i t As M e a s u r e m e n t u n i t
El P r o p e r t y S u b u n i t As M e a s u r e m e n t u n i t
tN P r o p e r t y S u b U n i t s P e r M a s t e r U n i t As D o u b l e
{read-only}
El P r o p e r t y T r a n s p a r e n c y As D o u b l e
P r o p e r t y Type As MsdModelType
El Sub U n s e l e c t A l 1 E l ements ( )
Sub U n s e l e c t E l ement ( E l ement As E l e m e n t )
El P r o p e r t y UORsPerMasterUni t As Doubl e { r e a d -
only1
P r o p e r t y UORsPerStorageUni t As D o u b l e
El P r o p e r t y UORsPerSubUnit As D o u b l e { r e a d - o n l y }
P r o p e r t y U p d a t e o r d e r As Long
El P r o p e r t y U s e s L i g h t s As B o o l e a n
F u n c t i o n W o r k i n g U n i t s T o D o u b l e ( V a 1 ue As S t r i n g )
As D o u b l e
I The Microstation Object Model I 227

Attachments
F u n c t i o n A d d ( F i 1 e S p e c i f i c a t i o n As S t r i n g ,
Model Name As S t r i n g , L o g i c a l Name As S t r i n g ,
D e s c r i p t i o n As S t r i n g , M a s t e r o r i g i n As P o i n t 3 d ,
R e f e r e n c e o r i g i n As P o i n t 3 d , [ T r u e s c a l e As
Bool ean = T r u e ] , [ D i s p l ay Immedi a t e l y As Bool ean
= T r u e ] ) As A t t a c h m e n t

F u n c t i o n A d d C o i n c i d e n t ( F i 1 e S p e c i f i c a t i o n As
S t r i n g , ModelName As S t r i n g , LogicalName As
S t r i n g , D e s c r i p t i o n As S t r i n g ,
C D i s p l ay Immedi a t e l y As Bool ean = T r u e ] ) As
Attachment
F u n c t i on AddCoi n c i d e n t 1 ( F i 1 eSpec f i c a t i o n As
S t r i n g , ModelName As S t r i n g , Log calName As
S t r i n g , D e s c r i p t i o n As S t r i n g , F ags As
M s d A d d A t t a c h m e n t F l a g s ) As A t t a c h m e n t
F u n c t i o n AddUsingNamedView(Fi1eSpecification
As S t r i n g , LogicalName As S t r i n g , D e s c r i p t i o n
As S t r i n g , ViewName As S t r i n g , C e n t e r p o i n t As
Poi n t 3 d , C D i s p l ay Immedi a t e l y As Bool ean =
T r u e ] ) As A t t a c h m e n t
F u n c t i o n AddUsingNamedViewl(Fi1eSpecification
As S t r i n g , ModelName As S t r i n g , LogicalName As
S t r i n g , D e s c r i p t i o n As S t r i n g , ViewName As
S t r i n g , C e n t e r p o i n t As P o i n t 3 d , F l a g s As
M s d A d d A t t a c h m e n t F l a g s ) As A t t a c h m e n t
P r o p e r t y Count As Long {read only}
F u n c t i o n F i ndByLogi c a l Name( Log calName As
S t r i n g ) As A t t a c h m e n t
P r o p e r t y I t e m As A t t a c h m e n t read-only}
Sub Remove(AttachmentSpecifier As V a r i a n t )

CadInputMessage
Property CommandKeyin As S t r i n g { r e a d - o n l y }
Property C u r s o r B u t t o n As Long { r e a d - o n l y }
Property I n p u t T y p e As MsdCadInputType { r e a d -
only}
Property K e y i n As S t r i n g { r e a d - o n l y }
Property P o i n t As P o i n t 3 d { r e a d - o n l y }
Property S c r e e n p o i n t As P o i n t 3 d { r e a d - o n l y }
Property View As View { r e a d - o n l y }
228 I Chapter 11:The Microstation Object Model - Objects I
CadInputQueue
F u n c t i o n G e t I n p u t ( C T y p e 1 As M s d C a d I n p u t T y p e =
m s d C a d I n p u t T y p e A n y 1 , [ T y p e 2 As
M s d C a d I n p u t T y p e l , [ T y p e 3 As M s d C a d I n p u t T y p e l ,
[ T y p e 4 As M s d C a d I n p u t T y p e l ) As C a d I n p u t M e s s a g e
Sub SendCommand(Command As S t r i n g ,
[ T r e a t L i k e K e y b o a r d I n p u t As B o o l e a n ] )
Sub S e n d D a t a P o i n t ( D a t a P 0 i n t As P o i n t 3 d ,
[ V i e w s p e c i f i e r As V a r i a n t ] , [ Q u a l i f i e r As
Long])
Sub S e n d D a t a P o i n t F o r L o c a t e ( E 1 e m e n t T o L o c a t e As
E l e m e n t , D a t a P o i n t As P o i n t 3 d , [ V i ewSpeci f i e r
As V a r i a n t ] , [ Q u a l i f i e r As L o n g ] )
Sub SendDragPoints(DownPoint As P o i n t 3 d ,
U p P o i n t As P o i n t 3 d , [ V i e w s p e c i f i e r As V a r i a n t ] ,
[ Q u a l i f i e r As L o n g ] )
Sub S e n d K e y i n ( K e y i n As S t r i n g )
Sub S e n d L a s t I n p u t O
Sub SendMessageToApplication(MdlApp1ication As
S t r i n g , Message As S t r i n g )
Sub S e n d R e s e t O
Sub S e n d T e n t a t i v e P o i n t ( D a t a P 0 i n t As P o i n t 3 d ,
V i e w s p e c i f i e r As V a r i a n t )

DesignFile
F u n c t i o n AddNewLevel(Leve1Name As S t r i n g ) As
Level
Sub A t t a c h C o l o r T a b l e(Co1 o r T a b l e As Col o r T a b l e )
P r o p e r t y A u t h o r As S t r i n g
P r o p e r t y C l i e n t As S t r i n g
Sub C l o s e 0
P r o p e r t y Comments As S t r i n g
P r o p e r t y Company As S t r i n g
l l F u n c t i o n CustomPropertyExists(Name As S t r i n g )
As B o o l e a n
P r o p e r t y D a t e c r e a t e d As D a t e { r e a d - o n l y }
P r o p e r t y D a t e L a s t P l o t t e d As D a t e { r e a d - o n l y }
P r o p e r t y D a t e L a s t S a v e d As D a t e { r e a d - o n l y }
I The Microstation Object Model I 229

P r o p e r t y D e f a u l t M o d e l R e f e r e n c e As
Model R e f e r e n c e {read-only}
Sub D e l e t e L e v e l ( L e v e l As L e v e l )
P r o p e r t y D i m e n s i o n s t y l e s As D i m e n s i o n s t y l e s
{ read-on1y 1
P r o p e r t y E d i t o r As S t r i n g { r e a d - o n l y }
F u n c t i o n E x t r a c t C o l o r T a b l e ( As Col o r T a b l e
P r o p e r t y Fence As Fence { r e a d - o n l y }
F u n c t i o n FindSavedView(NamePattern As S t r i n g ,
C P r e v i o u s l y F o u n d S a v e d V i e w As
S a v e d V i e w E l e m e n t l , [Namespace As S t r i n g ] ) As
SavedVi ewEl ement
P r o p e r t y F o n t s As F o n t s { r e a d - o n l y }
P r o p e r t y F o r m a t As M s d D e s i g n F i l e F o r m a t { r e a d -
only}
P r o p e r t y F o r m a t M a j o r V e r s i o n As Long { r e a d -
only}
P r o p e r t y F o r m a t M i n o r V e r s i o n As Long { r e a d -
only}
P r o p e r t y F u l l N a m e As S t r i n g { r e a d - o n l y }
F u n c t i o n G e t C u s t o m P r o p e r t y ( N a m e As S t r i n g ) As
Variant
F u n c t i o n GetElementByID(Element1D As DLong) As
Element
F u n c t i o n GetElementByID64(ElementID64 As
Empty) As E l e m e n t
F u n c t i o n G e t L a r g e s t E l e m e n t I D ( ) As DLong
Sub G e t L a r g e s t E l e m e n t I D 6 4 0
P r o p e r t y I s A c t i v e As B o o l e a n {read-only}
P r o p e r t y Keywords As S t r i n g
P r o p e r t y L a s t S a v e d B y As S t r i n g
P r o p e r t y L e v e l s As L e v e l s {read-only}
P r o p e r t y L i n e s t y l e s As L i n e s t y l e s {read-only}
P r o p e r t y Manager As S t r i n g
F u n c t i o n M d l F i l e O b j P O As Long
F u n c t i o n MdlModel R e f P ( As Long
P r o p e r t y M o d e l s As M o d e l R e f e r e n c e s { r e a d - o n l y }
P r o p e r t y Name As S t r i n g { r e a d - o n l y }
230 I Chapter 11 :The Microstation Object Model - Objects I
P r o p e r t y NonModel E l e m e n t c a c h e As E l e m e n t c a c h e
{read-only}
P r o p e r t y P a t h As S t r i n g { r e a d - o n l y }
P r o p e r t y R e v i s i o n N u m b e r As S t r i n g { r e a d - o n l y }
Sub R e w r i t e L e v e l s ( )
Sub S a v e 0
Sub SaveAs ( NewFi 1 eName As S t r i n g , [ O v e r w r i t e As
B o o l e a n = F a l s e ] , CNewFormat As
MsdDesignFileFormat =
msdDesignFileFormatCurrentl)
Sub S e t C u s t o m P r o p e r t y ( N a m e As S t r i n g , V a l u e As
Variant
P r o p e r t y S u b j e c t As S t r i n g
P r o p e r t y T a g S e t s As T a g S e t s { r e a d - o n l y }
P r o p e r t y T e x t s t y l e s As T e x t s t y l e s { r e a d - o n l y }
P r o p e r t y T i t l e As S t r i n g
P r o p e r t y T o t a l E d i t i n g T i m e As Long { r e a d - o n l y }
P r o p e r t y ViewGroups As ViewGroups { r e a d - o n l y }
P r o p e r t y Views As Views { r e a d - o n l y }

Element
Sub A d d D a t a b a s e L i n k ( L i n k T 0 A d d As D a t a b a s e L i n k )
F u n c t i o n A d d T a g ( T a g D e f i n i t i 0 n As
T a g D e f i n i t i o n ) As T a g E l e m e n t
F u n c t i o n A d d T a g s ( T a g S e t As T a g S e t ) As
TagEl e m e n t (
Sub A d d U s e r A t t r i b u t e D a t a ( A t t r i b u t e 1 D As Long,
A t t r i b u t e D a t a As D a t a B l o c k )
F u n c t i o n A p p a r e n t C o l o r ( V i e w As V i e w ) As Long
F u n c t i o n A p p a r e n t L i n e S t y l e ( V i e w As V i e w ) As
L ineStyl e
F u n c t i o n A p p a r e n t L i n e W e i g h t ( V i e w As V i e w ) As
Long
P r o p e r t y AsAppl ic a t i o n E l ement As
Appl i c a t i o n E l e m e n t { r e a d - o n l y }
P r o p e r t y A s A r c E l e m e n t As A r c E l e m e n t { r e a d -
only}
P r o p e r t y AsAuxiliaryCoordinateSystemElement As
AuxiliaryCoordinateSystemElement { r e a d - o n l y }
I The Microstation Object Model I 231

Property AsBsplineCurveElement As
BsplineCurveElement {read-only}
Property AsBsplineSurfaceElement A s
BsplineSurfaceElement {read-only}
Property AsCell Element As Cell Element {read-
only}
Property AsChainabl eEl ement A s
ChainableElement {read-only}
Property AsCl osedEl ement As C1 osedEl ement
{ read-on1y 1
Property AsCompl exEl ement A s Compl exEl ement
{ read-on1y }
Property AsCompl exShapeEl ement As
Compl exShapeEl ement {read-only}
Property AsCompl exStringEl ement A s
Compl exStringEl ement {read-only}
Property AsConeElement As ConeElement {read-
only}
Property AsCurveElement A s CurveElement
{ read-on1y }
Property AsDimensionElement As
Di mensi onEl ement {read -on1y}
Property AsDroppabl eEl ement A s
Droppabl eEl ement {read-only}
Property AsEllipseElement As EllipseElement
{ read-on1y 1
Property AsEll ipti cal El ement A s
Elliptical Element {read-only}
Property AsIntersectabl eEl ement As
Intersectabl eEl ement {read-only}
Property AsLineEl ement A s LineEl ement {read-
only}
Property AsMul ti LineEl ement As
Multi LineElement {read-only}
Property AsNamedGroupElement A s
NamedGroupElement {read-only}
Property AsPl anarEl ement As P1 anarEl ement
{ read-on1y 1
Property AsPointStringElement A s
PointStringElement {read-only}
232 I Chapter 11 :The Microstation Object Model - Objects I
Property AsPossi blyPl anarEl ement As
PossiblyPl anarElement {read-only}
Property AsSavedVi ewEl ement As
SavedViewElement {read-only}
Property AsShapeElement As ShapeElement
{read-only}
Property AsSharedCell Defi ni ti onEl ement As
SharedCell DefinitionElement {read-only}
Property AsSharedCell Element As
SharedCell Element {read-only}
Property AsTagElement As TagElement {read-
only1
Property AsTextElement As TextElement {read-
only1
Property AsTextNodeEl ement As TextNodeEl ement
{read-only}
Property AsTraversabl eEl ement As
Traversabl eEl ement {read-only}
Property AsVertexList As VertexList {read-
only1
Property Cache As Elementcache {read-only}
Property CacheIndex As Long {read-only}
Property C1 ass As MsdEl ementCl ass
Function C l o n e 0 As Element
Property Color As Long
Function ConstructVertexList(To1erance As
Double) As P o i n t 3 d O
Property DateLastModified As Date {read-only}
S u b Del eteAl1 Tags ( )
S u b Del eteAl1 XData ( )
S u b DeleteTag(Tag As TagElement)
S u b DeleteTagSet(TagSet As TagSet)
Function DeleteUserAttributeData(Attribute1D
As Long, Index As Integer) As Integer
S u b DeleteXData(App1icationName As String)
S u b DrawToFile(Fi1eName As String, Width As
Long, Height As Long, CDrawBackGround As
Boolean = False])
Property Fi 1 ePosi ti on As Long {read-only}
I The Microstation Object Model I 233

I4 F u n c t i o n GetContainingNamedGroupsO As
NamedGroupEl e m e n t ( 1
I4 F u n c t i o n GetDatabaseLinks([DatabaseType As
M s d D a t a b a s e L i n k a g e l , [ E n t i t y N u m b e r As L o n g ] )
As D a t a b a s e L i n k ( )
I4 F u n c t i o n G e t P i c t u r e ( W i d t h As Long, He g h t As
Long, CDrawBackGround As B o o l e a n = Fa s e l l As
Unknown
I4 F u n c t i o n G e t R e l a t e d E l e m e n t s ( L o c k e d As 3001 e a n ,
C T r a v e r s e T y p e As MsdMemberTraverseType =
msdMemberTraverseCopy1, [ N e w T r a v e r s a l As
B o o l ean = T r u e 1 ) As E l e m e n t E n u m e r a t o r
I4 F u n c t i o n G e t T a g ( T a g S e t As T a g S e t , TagName As
S t r i n g ) As T a g E l e m e n t
I4 F u n c t i o n G e t T a g s O As T a g E l e m e n t O
I4 F u n c t i o n G e t U s e r A t t r i b u t e D a t a ( A t t r i b u t e 1 D As
L o n g ) As D a t a B l o c k (
I4 F u n c t i o n GetXData(App1icationName As S t r i n g )
As XDatumO
I4 F u n c t i o n GetXDataApplicationNamesO As
String00
I4 P r o p e r t y G r a p h i c G r o u p As Long
I4 F u n c t i o n H a s A n y D a t a b a s e L i n k s ( [ D a t a b a s e T y p e As
M s d D a t a b a s e L i n k a g e l , [ E n t i t y N u m b e r As L o n g ] )
As B o o l e a n
I4 P r o p e r t y HasAnyTags As B o o l e a n { r e a d - o n l y }
I4 F u n c t i o n H a s A n y X D a t a O As B o o l e a n
I4 F u n c t i o n HasXData(App1icationName As S t r i n g )
As B o o l e a n
I4 P r o p e r t y I D As DLong { r e a d - o n l y }
I4 P r o p e r t y I D 6 4 As Empty { r e a d - o n l y }
I4 P r o p e r t y I n D i s p l a y S e t As B o o l ean
I4 P r o p e r t y I s A p p l i c a t i o n E 1 ement As B o o l ean
{read-on Y }
I4 P r o p e r t y I s A r c E l ement As B o o l ean { r e a d - o n l y }
I4 P r o p e r t y IsAuxiliaryCoordinateSystemElement As
B o o l ean r e a d - o n 1 y }
I4 P r o p e r t y I s B s p l i n e C u r v e E l ement As B o o l ean
{read-on Y }
234 I Chapter 11:The Microstation Object Model - Objects I
El P r o p e r t y I s B s p l i n e S u r f a c e E l e m e n t As Boolean
{read-only}
P r o p e r t y I s C e l l Element As Boolean { r e a d - o n l y }
P r o p e r t y I s C h a i n a b l e E l e m e n t As Boolean { r e a d -
only}
P r o p e r t y IsCl osedEl ement As Bool e a n { r e a d -
only1
P r o p e r t y IsCompl exEl ement As Bool e a n { r e a d -
only}
P r o p e r t y IsCompl exShapeEl ement As Bool e a n
{read-only}
P r o p e r t y IsCompl e x S t r i ngEl ement As Bool e a n
{ read-on1y }
P r o p e r t y IsComponentElement As Boo e a n { r e a d -
only1
P r o p e r t y IsConeEl ement As Bool e a n r e a d - o n 1 y }
P r o p e r t y I s C u r v e E l ement As Bool e a n { r e a d - o n 1 y }
P r o p e r t y I s D i m e n s i o n E l e m e n t As Boo e a n { r e a d -
only}
P r o p e r t y I s D r o p p a b l eEl ement As Bool e a n { r e a d -
only1
P r o p e r t y I s E l 1 i pseEl ement As Bool e a n { r e a d -
only}
P r o p e r t y I s E l 1 i p t i c a l El ement As Bool e a n
{read-on Y}
P r o p e r t y I s G r a p h i c a l As Boolean { r e a d - o n l y }
P r o p e r t y I s H i d d e n As Boolean
P r o p e r t y I s I n t e r s e c t a b l eEl ement As Bool e a n
{ r e a d - o n Yl
P r o p e r t y I s L i n e E l e m e n t As Boolean { r e a d - o n l y }
P r o p e r t y I s L o c k e d As Boolean
P r o p e r t y I s M o d i f i e d As Boolean { r e a d - o n l y }
P r o p e r t y IsMul t i Li neEl ement As Bool e a n { r e a d -
only}
P r o p e r t y IsNamedGroupEl ement As Bool e a n
{read-only}
P r o p e r t y IsNew As Boolean { r e a d - o n l y }
P r o p e r t y I s P l a n a r E l ement As Bool e a n { r e a d -
only1
I The Microstation Object Model I 235

Property IsPointStringEl ement As Bool ean


{ read-on1y 1
Property IsPossi blyPl anarEl ement A s Bool ean
{ read-on1y }
Property IsSavedViewElement As Boolean {read-
only}
Property IsShapeElement A s Boolean {read-only}
Property IsSharedCell DefinitionElement As
Boolean {read-only}
Property IsSharedCell Element A s Bool ean
{ read-on1y }
Property IsSnappable As Boolean
Property IsTagElement A s Boolean {read-only}
Property IsTextElement As Boolean {read-only}
Property IsTextNodeElement A s Boolean {read-
only}
Property IsTraversabl eEl ement As Bool ean
{ read-on1y 1
Property IsValid A s Boolean {read-only}
Property IsVertexList As Boolean {read-only}
Property Level A s Level
Property Linestyle As Linestyle
Property Lineweight A s Long
Function Mdl El ementDescrP( [Detach As Bool eanl)
As Long
Sub Mirror(Point1 A s Point3d, Point2 A s
Poi nt3d)
Sub Mirror3d(PlanePointl As Point3d,
Planepoint2 As Point3d, PlanePoint3 As Point3d)
Property Model Reference A s Model Reference
{ read-on1y }
Sub Move(0ffset As Point3d)
Sub Parti a1 Del ete( Parti a1 1 A s El ement,
Partial2 As Element, Point1 As Point3d, Point2
As Poi nt3d, Sel ector A s Poi nt3d, Vi ewSpeci fi er
As Variant)
Property Range As Range3d {read-only)
Sub Redraw(CDrawMode A s MsdDrawingMode =
msdDrawi ngModeNormal1)
236 I Chapter 11:The Microstation Object Model - Objects I
Sub RemoveAll D a t a b a s e L i n k s ( )
F u n c t i o n RemoveDatabaseLink(DatabaseType As
M s d D a t a b a s e L i n k a g e , [MSLinkNumber As L o n g ] ,
[ E n t i t y N u m b e r As L o n g ] ) As Long
Sub R e w r i t e 0
Sub R o t a t e ( P i v o t As P o i n t 3 d , AboutX As D o u b l e ,
AboutY As D o u b l e , A b o u t Z As D o u b l e )
Sub R o t a t e A b o u t Z ( P i v o t As P o i n t 3 d , A n g l e As
Doubl e 1
Sub S c a l e A l l ( O r i g i n As P o i n t 3 d , X F a c t o r As
D o u b l e , Y F a c t o r As D o u b l e , Z F a c t o r As D o u b l e )
Sub S c a l e U n i f o r m ( 0 r i g i n As P o i n t 3 d ,
S c a l e F a c t o r As D o u b l e )
Sub SetXData(App1icationName As S t r i n g ,
NewXDataO As XDatum)
P r o p e r t y S u b t y p e As M s d E l e m e n t S u b t y p e { r e a d -
only1
Sub T r a n s f o r m ( T r a n s f o r m 3 d As T r a n s f o r m 3 d )
P r o p e r t y Type As MsdElementType { r e a d - o n l y }
P r o p e r t y URL As S t r i n g { r e a d - o n l y }
P r o p e r t y U R L T i t l e As S t r i n g { r e a d - o n l y }

ElementEnumerator
F u n c t i o n B u i l d A r r a y F r o m C o n t e n t s O As E l e m e n t 0
F u n c t i o n C l o n e 0 As E l e m e n t E n u m e r a t o r
P r o p e r t y C u r r e n t As E l e m e n t { r e a d - o n l y }
F u n c t i o n M o v e N e x t O As B o o l e a n
Sub R e s e t ( )

Elementscancriteria
Sub E x c l u d e A l 1 C1 a s s e s ( )
Sub E x c l u d e A l 1 Col o r s ( )
Sub Excl udeAl1 Level s ( )
Sub E x c l u d e A l 1 L i n e S t y l es ( )
Sub E x c l u d e A l 1 L i neWei g h t s ( )
Sub Excl udeAl1Subtypes ( )
Sub E x c l u d e A l 1 Types ( )
Sub Excl udeGraphi c a l ( )
I The Microstation Object Model I 237

Sub Excl udeNonGraphi cal (


Sub Incl udeCl ass( El emCl ass A s MsdEl ementCl ass)
Sub Incl udeCol or(Co1 orIndex As Long)
Sub Incl udeLevel (Level A s Level )
Sub Incl udeLineSty1 e( LineStyl e As LineStyl e)
Sub Incl u d e L i n e W e i g h t ( L i n e W e i g h t A s Long)
Sub Incl udeOnlyCel1 (Cell Name As String)
Sub IncludeOnlyFilePositionRange(Min A s Long,
Max As Long)
Sub Incl udeOnlyGraphi cGroup(Graphi cGroupNumber
As Long)
Sub Incl udeOnlyHol e( )
Sub IncludeOnlyInvisibleO
Sub Incl udeOnlyLocked()
Sub IncludeOnlyModified(
Sub Incl udeOnlyModifiedRange(Min A s Date, [Max
As Date])
Sub Incl udeOnlyNew(
Sub Incl udeOnlyNonP1 anar( )
Sub Incl udeOnlyNonSnappab1 e(
Sub Incl udeOnlyOl d( )
Sub Incl udeOnlyPl anar(
Sub Incl udeOnlySnappab1 e( )
Sub Incl udeOnlySol id(
Sub Incl udeOnlyUnl ocked( )
Sub IncludeOnlyUnmodified( 1
Sub IncludeOnlyUserAttribute(UserAttribute1D
As Long)
Sub IncludeOnlyVisibleO
Sub Incl u d e O n l y W i t h i n R a n g e ( R a n g e A s Range3d)
Sub IncludeSubtype(Long As Long)
Sub Incl udeType(Type A s MsdEl ementType)
Sub R e s e t 0

Level
Sub AddUserAttributeData(Attribute1D A s Long,
Attri buteData A s DataBl ock)
238 I Chapter 11 :The Microstation Object Model - Objects I
Function DeleteUserAttributeData(Attribute1D
As Long, Index As Integer) As Integer
Property Description As String
Property El ementAccess As
MsdLevel El ementAccess
Property ElementColor As Long
Property El ementLi neStyl e As Li neStyl e
Property El ement Li neWei g h t As Long
Function GetUserAttr buteData(Attribute1D As
Long) As DataBl ock()
Property ID As Long read-on1 y }
Property IsActive As Bool ean
Property IsDi spl ayed As Boolean
Property IsDi spl ayedInVi e w As Bool ean
Property IsEffectivelyDisplayedInView As
Boolean {read-only}
Property IsFromLevel Library As Boolean {read-
only1
Property IsFrozen As Boolean
Property IsInUse As Boolean {read-only}
Function IsInUseWithinModel (Model As
Model Reference) As Bool ean
Property IsLocked As Boolean
Property Name As String
Property Number As Long
Property OverrideColor As Long
Property OverrideLi neStyl e As Li neStyl e
Property OverrideLineWeight As Long
Property ParentLevel As Level
Property Plot As Boolean
Property UsingOverrideColor As Boolean
Property UsingOverrideLineStyle As Boolean
Property UsingOverrideLineWeight As Boolean

ModelReference
Sub Activate0
S u b AddEl ement (El ement As El ement)
I The Microstation Object Model I 239

Sub A d d E l e m e n t s ( E l e m e n t s 0 As - E l e m e n t )
F u n c t i o n AddNewNamedGroup([Name As S t r i n g ] ,
[ D e s c r i p t i o n As S t r i n g ] ) As NamedGroupElement
Sub A d d U s e r A t t r i b u t e D a t a ( A t t r i b u t e 1 D As Long,
A t t r i b u t e D a t a As D a t a B l o c k )
P r o p e r t y AnyEl e m e n t s S e l e c t e d As B o o l ean
{ read-on1y }
P r o p e r t y A s A t t a c h m e n t As A t t a c h m e n t { r e a d -
only}
P r o p e r t y A t t a c h m e n t s As A t t a c h m e n t s { r e a d -
only}
P r o p e r t y CanBePl acedAsCel1 As B o o l ean
P r o p e r t y C e l l Type As MsdCel 1 Type
P r o p e r t y C o n t r o l E l e m e n t C a c h e As E l e m e n t c a c h e
{ read-on1y 1
F u n c t i o n CopyEl e m e n t ( E l ement As E l e m e n t ,
CCopyContext As C o p y C o n t e x t l ) As E l e m e n t
Sub Del e t e A l 1 X D a t a (
F u n c t i o n DeleteUserAttributeData(Attribute1D
As Long, I n d e x As I n t e g e r ) As I n t e g e r
Sub DeleteXData(App1icationName As S t r i n g )
P r o p e r t y D e s c r i p t i o n As S t r i n g
P r o p e r t y D e s i g n F i l e As D e s i g n F i l e { r e a d - o n l y }
F u n c t i o n D o u b l e T o W o r k i n g U n i t s ( V a 1 u e As D o u b l e )
As S t r i n g
Function
E l ementCacheContainingFi1ePosi t i o n ( F i l ePosi t i o
n As Long, CCacheIndex As L o n g ] ) As
E l ementcache
F u n c t i o n GetElementByID(Element1D As DLong) As
Element
F u n c t i o n GetElementByID64(ElementID64 As
Empty) As E l e m e n t
F u n c t i o n G e t L a s t V a l i d G r a p h i c a 1 E l e m e n t ( ) As
Element
F u n c t i o n GetNamedGroup(GroupName As S t r i n g ) As
NamedGroupEl ement
F u n c t i o n G e t S e l e c t e d E l e m e n t s ( ) As
E l ementEnumerator
240 I Chapter 11:The Microstation Object Model - Objects I
El F u n c t i o n G e t S h e e t D e f i n i t i o n O As
SheetDefinition
El F u n c t i o n G e t U s e r A t t r i b u t e D a t a ( A t t r i b u t e 1 D As
L o n g ) As D a t a B l o c k ( )
F u n c t i o n GetXData(App1icationName As S t r i n g )
As XDatumO
El F u n c t i o n GetXDataApplicationNamesO As
String( )( )
P r o p e r t y G1 o b a l Ori g i n As P o i n t 3 d { r e a d - o n l y }
El P r o p e r t y G r a p h i c a l E l e m e n t c a c h e As E l e m e n t c a c h e
{read-only}
F u n c t i o n H a s A n y X D a t a O As B o o l e a n
El F u n c t i o n HasXData(App1 ic a t i onName As S t r i n g )
As B o o l e a n
P r o p e r t y I s 3 D As B o o l e a n { r e a d - o n l y }
El P r o p e r t y I s A c t i v e As B o o l e a n { r e a d - o n l y }
P r o p e r t y I s A t t a c h m e n t As B o o l e a n { r e a d - o n l y }
El P r o p e r t y I s E l ementSel e c t e d As B o o l ean { r e a d -
only}
P r o p e r t y I s L o c k e d As B o o l e a n
El P r o p e r t y I s R e a d O n l y As B o o l e a n { r e a d - o n l y }
P r o p e r t y L e v e l s As L e v e l s { r e a d - o n l y }
El P r o p e r t y M a s t e r u n i t As M e a s u r e m e n t u n i t
El F u n c t i o n M d l M o d e l R e f P O As Long
El P r o p e r t y Name As S t r i n g
P r o p e r t y P a r e n t M o d e l R e f e r e n c e As
Model R e f e r e n c e {read-only}
El Sub PropagateAnnotationScaleO
F u n c t i o n Range( I n c l u d e A t t a c h m e n t s As Boo e a n )
As Range3d
El Sub RemoveEl ement ( E l ement As E l e m e n t )
Sub Rep1 a c e E l ement ( 0 1 d E l ement As E l ement
NewEl ement As E l e m e n t )
El F u n c t i o n S c a n ( [ S c a n C r i t e r i a As
E l e m e n t S c a n C r i t e r i a l ) As E l e m e n t E n u m e r a t o r
tN Sub S e l e c t E l ement ( E l ement As E l ement ,
[ D i s p l ayAsSel e c t e d As B o o l ean = T r u e ] )
I Review I 241

Sub S e t S h e e t D e f i n i t i o n ( N e w D e f i n i t i 0 n As
SheetDefi n ition)
Sub SetXData(App1icationName As S t r i n g ,
NewXDataO As XDatum)
P r o p e r t y S t o r a g e u n i t As MeasurementUni
P r o p e r t y S u b u n i t As M e a s u r e m e n t u n i t
P r o p e r t y S u b U n i t s P e r M a s t e r U n i t As Doub e
{ read-on1y 1
P r o p e r t y Type As MsdModelType
Sub U n s e l e c t A l 1 E l e m e n t s (
Sub U n s e l e c t E l e m e n t ( E l ement As E l e m e n t )
P r o p e r t y UORsPerMasterUni t As D o u b l e { r e a d -
only}
P r o p e r t y UORsPerStorageUni t As D o u b l e
P r o p e r t y UORsPerSubUnit As D o u b l e { r e a d - o n l y }
F u n c t i o n W o r k i n g U n i t s T o D o u b l e ( V a 1 u e As S t r i n g )
As D o u b l e

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.
.

12 The Microstation Object


Model - Enums

What is an Enum? Enum is an abbreviation for enumeration, a


collection of constants that can be used in our code.
Lets consider the following enumeration:

MSDDESIGNFILEFORMAT
msdDesi g n F i 1 e F o r m a t C u r r e n t = 0
msdDesi g n F i 1 eFormatDWG = 3
msdDesi g n F i 1 eFormatDXF = 4
msdDesignFileFormatUnknown = -1
msdDesi g n F i 1 eFormatV7 = 1
msdDesi g n F i 1 eFormatV8 = 2
The enumeration name is MsdDesignFileFormat.It has six members
with values ranging from - 1 to 4. Each member in an enumeration has a
name and a value. The enumeration member
msdDesignFileFormatCurrent has a value of 0. As we saw in the
previous chapter, some properties and methods make use of these
enumerations. For example,

243
244 I Chapter 12: The Microstation Object Model - Enums I
S u b SaveAs(NewFi1eName As String, [Overwrite As -

Boo1 ean = Fa1 sel , [NewFormat A s MsdDesignFi 1 eFormat -

= msdDesignFileFormatCurrent1)

The SaveAs method is found under the DesignFile object. When we use
it, we can specify a file name, whether an existing file should be over-
written, and the file format to be used. The data type for
NewFileName is String. The value type for Overwrite is Boolean.
The value type for NewFormat is MsdDesignFileFormat. The
NewFormat parameter utilizes the MsdDesignFileFormat
enumeration. As we use the SaveAs method, we see the following:
ACtiveDeSignFile. S P Y ~ A S test.dgn, True,

While working in VBA, when we come to a parameter that utilizes an


enumeration, we see the list of the members of that enumeration. We are
not shown the value of each member.
Enumerations provide several benefits, with one of the largest being that
we can more easily see the desired parameter results as we look at our
code. In other words, seeing msdDesignFileFormatDWG is clearer
than seeing the number 3 in the NewFormat parameter.
There are two ways to use enumerators. One is to use the Name.Member
format, such as:

A c t i v e D e s i g n F i 1e.SaveAs t e s t . d g n , T r u e , ~

MsdDesignFileFormat.msdDesignFi1eFormatDWG
The other way is to use the member name without the enumerator
name:

ActiveDesignFi1e.SaveAs test.dgn, T r u e , rnsdDesignFileFormatDWG

Names of enumeration members often begin with the enumeration


name or a shortened version of the enumeration name. The above
examples use the MsdDesignFileFormat enumeration with the
msdDesignFileFormatDWG member. Notice how the enumeration
name is used to begin the member name. Occasionally, an abbreviation
is used such as with the MsdCoordinateAccuracyenumeration. The
members of this enumeration begin with msdAccuracy instead of the
full enumeration name msdCoordinateAccuracy: It should be noted
I The Enumeration List I 245

that all Microstation enumerations begin with the three-letter


designation M sd and all member names begin with msd.
Now that we have discussed what enumerations are and how they can be
used, lets examine the enumerations available in Microstation VBA.

THEENUMERATIONLIST
MsdACSType
msdACSTypeCy1 i ndri cal = 2
msdACSTypeNone = 0
msdACSTypeRectangu1 ar = 1
msdACSTypeSpheri cal = 3

MsdAddAttachmentFlags
msdAddAttachmentElementsVisible = 4
msdAddAttachmentFlagCoincidentWorld = 2
msdAddAttachmentFlagNone = 0
msdAddAttachmentFlagTrueScale = 1

MsdAngleAccuracy
msdAngl eAccuracyO = 0
msdAngl eAccuracy1 = 1
msdAngl eAccuracy2 = 2
msdAngl eAccuracy3 = 3
msdAngl eAccuracy4 = 4
msdAngl eAccuracy5 = 5
msdAngl eAccuracy6 = 6
msdAngl eAccuracy7 = 7
msdAngl eAccuracy8 = 8

MsdAngleFormat
msdFormatDD-0000 = 0
msdFormatDD-MM-SS = 1
msdFormatGradians = 2
msdFormatRadi ans = 3
246 I Chapter 12: The Microstation Object Model - Enums I

MsdAngleMode
msdAngl eModeAzimuth = 1
msdAngl eModeBeari ng = 2
msdAngl eModeConventi onal = 0

MsdAttachMode
msdAttachNone = 1
msdAttachReference = 3

MsdBsplineCurveOffsetCuspType
msdBsplineCurveOffsetCuspArc = 4
msdBsplineCurveOffsetCuspChamfer = 1
msdBsplineCurveOffsetCuspJump = 0
msdBsplineCurveOffsetCuspParabola = 3
msdBsplineCurveOffsetCuspPoint = 2

MsdBsplineCurveType
msdBspl i neCurveCi rcl e = 3
msdBspl i neCurveCi rcul arArc = 2
msdBsplineCurveEllipse = 5
msdBspl i neCurveEl1 i pti cal Arc = 4
msdBsplineCurveGenera1 = 0
msdBsplineCurveHyperbolicArc = 7
msdBsplineCurveLine = 1
msdBsplineCurveParabolicArc = 6

MsdBsplineParametrizationType
msdBspl ineparametri zati onCentri petal = 2
msdBsplineParametrizationChordLength = 1
msdBsplineParametrizationInherited = 3
msdBspl ineparametri zati onUni form = 0

MsdBsplineSurfaceDirection
msdBsplineSurfaceU = 0
msdBsplineSurfaceV = 1

MsdBsplineSurfaceType
msdBsplineSurfaceCone = 3
msdBsplineSurfaceGenera1 = 0
I The Enumeration List I 247

msdBspl i neSurfaceP1 ane = 1


msdBsplineSurfaceRevolution = 6
msdBsplineSurfaceRightCylinder = 2
msdBsplineSurfaceRuledSurface = 8
msdBsplineSurfaceSphere = 4
msdBsplineSurfaceTabCylinder = 7
msdBsplineSurfaceTorus = 5

MsdCadInputType
msdCadInputTypeAny = 5
msdCadInputTypeCommand = 1
msdCadInputTypeDataPoint = 3
msdCadInputTypeKeyin = 4
msdCadInputTypeReset = 2
msdCadInputTypeUnassignedCB = 6

MsdCelIType
msdCel1 TypeGraphi c = 0
msdCellTypeMenu = 1
msdCel1 TypePoi n t = 7

MsdChangePropagation
msdChangePropagationAlways = 2
msdChangePropagationGroupLock = 0
msdChangePropagationNever = 1
MsdChangeTrackAction
msdChangeTrackActionAdd = 2
msdChangeTrackActionAppData = 8
msdChangeTrackActionDelete = 1
msdChangeTrackActionDrop = 6
msdChangeTrackActionMark = 7
msdChangeTrackActionModelAdd = 9
m s d C h a n g e T r a c k A c t i o n M o d e 1 Delete = 10
msdChangeTrackActionModify = 3
msdChangeTrackActionModifyFence = 5
msdChangeTrackActionNewFilePositionAndModify = 4
248 I Chapter 12: The Microstation Object Model - Enums I

MsdCom mandResuIt
msdCommandResu1 t3dLi brary2dFi 1 e = 50
msdCommandResu1 t3dOnly = 39
msdCommandResultAcceptQuery = 68
msdCommandResu1 tBadCel1 Name = 47
msdCommandResu1 tCel1 Deleted = 59
msdCommandResu1 tCel1 Exists = 55
msdCommandResu1 tCel1 Li braryNotFound = 1 2
msdCommandResultCellNestingError = 43
msdCommandResultCellNotFound = 44
msdCommandResu1 tEl ementNotFound = 21
msdCommandResu1 tEmptyFence = 27
msdCommandResu1 tFi 1 eReadOnly = 287
msdCommandResultIllegalDefinition = 23
msdCommandResultInvalidReferenceOperation = 481
msdCommandResultNeedCharacters = 27
msdCommandResultNoActiveCel1 = 19
msdCommandResu1 tNoCel1 Library = 54
msdCommandResultNoFenceActive = 15
msdCommandResu1 tNoOri gi n = 56
msdCommandResu1 tOffDesignP1 ane = 22
msdCommandResultReferenceNotFound = 7
msdCommandResultSuccess = 0
msdCommandResultUnknownCommand = 16
msdCommandResu1 tVi ewNotFound = 1 8

MsdConversionMode
msdConversionModeAlways = 1
msdConversionModeNever = 0
msdConversionModePrompt = 2

MsdCoordinateAccuracy
msdAccuracy0 = 1
msdAccuracyl = 2
msdAccuracyl6th = 56
msdAccuracy2 = 3
msdAccuracy3 = 4
I The Enumeration List I 249

msdAccuracy32nd = 120
msdAccuracy4 = 5
msdAccuracy4th = 8
msdAccuracy5 = 6
msdAccuracy6 = 7
m s d A c c u r a c y 6 4 t h = 248
m s d A c c u r a c y 8 t h = 24
msdAccuracyHa1 f = 0

MsdCoordinateFormat
msdMasterUnits = 1
msdSubUnits = 0
msdWorkingUnits = 2

MsdCopyContextLevelOption
msdCopyContextLeve1 AlreadyRemapped = 4
msdCopyContextLeve1 B y U s e r P r e f e r e n c e = 0
msdCopyContextLevelCopyAlways = 3
msdCopyContextLevelCopyIfDifferent = 2
msdCopyContextLevelCopyIfNotFound = 1
MsdCopyViewPort
msdCopyViewPortApplyAspectRatio = 2
msdCopyViewPortApplySize = 3
msdCopyViewPortApplySizeAndPosition = 4
msdCopyViewPortKeepCurrent = 0

MsdDatabaseLinkage
msdDatabaseLinkageInformix = 1
m s d D a t a b a s e L i n k a g e I n g r e s = 32
msdDatabaseLinkageOdbc = 1 2 8
msdDatabaseLinkageO1 eDb = 256
msdDatabaseLinkageOrac1e = 8
msdDatabaseLinkageXBase = 4

MsdDataEntryRegionJustification
msdDataEntryRegionJustificationCenter = 0
msdData E n t r y Regi o n J u s t i f ica t i on L e f t = - 1
msdData E n t r y Regi on J u s t if ic a t ion R i g h t = 1
250 I Chapter 12: The Microstation Object Model - Enums I

MsdDesignFileFormat
msdDesignFileFormatCurrent = 0
msdDesignFileFormatDWG = 3
msdDesignFileFormatDXF = 4
msdDesignFileFormatUnknown = -1
msdDesignFileFormatV7 = 1
msdDesignFileFormatV8 = 2

MsdDevelopableElementOutputType
msdDevel o p a b l eCones = 4
msdDevel o p a b l eConesPl a n a r = 5
msdDevel o p a b l eRul e L i n e s = 0
msdDevel o p a b l eRul e L i n e s P l a n a r = 1
msdDevel o p a b l eShapes = 2
msdDevel o p a b l eShapesPl a n a r = 3

MsdDialogBoxResult
msdDi a1 ogBoxResul t A p p l y = 1
msdDi a1 ogBoxResul t C a n c e l = 4
msdDi a1 ogBoxResul t D e f a u l t = 5
msdDi a1 ogBoxResul t H e l p = 1 0
msdDi a1 ogBoxResul t N o = 7
msdDi a1 ogBoxResul t O K = 3
msdDi a1 ogBoxResul t R e s e t = 2
msdDi a1 ogBoxResul t R e t r y = 8
msdDi a1 ogBoxResul t S t o p = 9
msdDi a1 ogBoxResul t Y e s = 6
msdDi a1 ogBoxResul t Y e s T o A l 1 = 11

MsdDimAccuracy
msdDimAccuracy0 = 0
msdDimAccuracy1 = 129
msdDimAccuracyl6th = 8
msdDimAccuracy2 = 1 3 0
msdDimAccuracy3 = 1 3 2
msdDimAccuracy32nd = 1 6
msdDimAccuracy4 = 1 3 6
msdDimAccuracy4th = 2
I The Enumeration List I 251

msdDimAccuracy5 = 144
msdDimAccuracy6 = 160
msdDimAccuracy64th = 32
msdDimAccuracy7 = 192
msdDimAccuracy8 = 128
msdDimAccuracy8th = 4
msdDimAccuracyHa1 f = 1
msdDimAccuracySci 1 = 64
msdDimAccuracySci2 = 65
msdDimAccuracySci3 = 66
msdDimAccuracySci4 = 67
msdDimAccuracySci5 = 68
msdDimAccuracySci 6 = 69
msdDimAccuracySci7 = 70
msdDimAccuracySci8 = 7 1

MsdDimAlignment
msdDimAl ig n m e n t A r b i t r a r y = 3
msdDimAlignmentDrawing = 1
msdDimAlignmentTrue = 2
msdDimAlignmentView = 0

MsdDimAlternateThresholdComparison
MsdDimAlternateThresholdComparisonGreater = 1
MsdDimAl t e r n a t e T h r e s h o l d C o m p a r i s o n G r e a t e r O r E q u a 1 = 3
MsdDimAlternateThresholdComparisonLess = 0
MsdDimAl t e r n a t e T h r e s h o 1 dCompari sonLessOrEqual = 2

MsdDimAngleMeasure
MsdDimAngl eMeasureAng1 e = 1
MsdDimAngl e M e a s u r e A r c L e n g t h = 0

MsdDimBallAndChainAlignment
msdDimBallAndChainAlignmentAuto = 0
msdDimBallAndChainAlignmentLeft 1 =

msdDimBallAndChainA1 i g n m e n t R i g h t = 2
252 I Chapter 12: The Microstation Object Model - Enums I
MsdDimBallAndChainChainType
msdDimBall AndChainChainTypeArc = 2
m s d D i m B a l l AndChainChainTypeBSpline = 3
msdDimBallAndChainChainTypeLine = 1
m s d D i m B a l l AndChainChainTypeNone = 0

MsdDimCustomSymbol
msdDimCustomSymbolCharacter = 1
msdDimCustomSymbo1 D e f a u l t = 0

MsdDimDMSPrecisionMode
MsdDimDMSPreci s i onModeFixed = 0
MsdDimDMSPreci s i onModeFl o a t i n g = 1

MsdDimLabe1LineFormat
MsdDimLabel L i neFormatAng1 eAbove = 3
MsdDimLabel L i neFormatAng1 e B e l ow = 5
MsdDimLabel L i neFormatAng1 e O v e r L e n g t h = 1
MsdDimLabel L i n e F o r m a t L e n g t h A b o v e = 2
MsdDimLabel L i n e F o r m a t L e n g t h A n g 1 eAbove = 6
MsdDimLabel L i n e F o r m a t L e n g t h A n g 1 e B e l ow = 7
MsdDimLabel L i n e F o r m a t L e n g t h B e l ow = 4
MsdDimLabel L i n e F o r m a t S t a n d a r d = 0

MsdDimMLNoteFrameType
msdDimMLNoteFrameTypeBox = 2
msdDimMLNoteFrameTypeLine = 1
msdDimMLNoteFrameTypeNone = 0

MsdDimMLNoteJustification
msdDimMLNoteJusti f i c a t i o n c e n t e r = 3
msdDimMLNoteJusti f i c a t i onDynami c = 2
msdDimMLNoteJustificationLeft = 0
msdDimMLNoteJustificationRight = 1

MsdDimNoteHorizontalAttachment
msdDimNoteHorizontalAttachmentAuto = 0
msdDimNoteHorizontalAttachmentLeft = 1
I The Enumeration List I 253

msdDimNoteHorizontalAttachmentRight = 2

MsdDimNoteLeaderType
MsdDimNoteLeaderTypeCurve = 1
MsdDimNoteLeaderTypeLine = 0

MsdDimNoteTextRotation
msdDimNoteTextRotationHorizonta1 = 0
msdDimNoteTextRotationInline = 2
msdDirnNoteTextRotationVertica1 = 1

MsdDimNoteVerticaIAttachment
msdDimNoteVertica1AttachmentBottom = 4
msdDimNoteVertica1AttachmentBottomLine = 3
msdDimNoteVerticalAttachmentDynamicCorner = 6
msdDimNoteVerticalAttachmentDynamicLine = 5
msdDimNoteVerti c a l AttachmentMiddl e = 2
msdDimNoteVertica1AttachmentTop = 0
msdDimNoteVerticalAttachmentTopLine = 1
msdDimNoteVertica1Attachmentunderline = 7

MsdDimNoteVerticalJustification
msdDimNoteVertica1 J u s t i f i c a t i o n B o t t o m = 2
msdDimNoteVerti c a l J u s t i f i c a t oncenter = 1
m s d D i m N o t e V e r t i c a 1 J u s t i f i c a t onDynamic = 3
m s d D i m N o t e V e r t i c a l J u s t i f i c a t onTop = 0

MsdDimPlacementTextPosition
msdDimPlacementTextPos t i o n A u t o = 2
msdDimPlacementTextPos t i o n M a n u a l = 0
msdDimPlacementTextPos t i o n S e m i A u t o = 1

MsdDimRadialMode
msdDimRadi a1 M o d e c e n t e r M a r k = 0
msdDimRadi a1 ModeDi a m e t e r = 3
msdDimRadi a1 ModeDi a m e t e r E x t e n d e d = 4
msdDimRadi a1 ModeRadi us = 1
msdDimRadi a1 ModeRadi u s E x t e n d e d = 2
254 I Chapter 12: The Microstation Object Model - Enums I

MsdDimStackedFractionAlignment
MsdDimStackedFractionAlignmentBottom = 2
MsdDimStackedFractionAlignmentCenter = 1
MsdDimStackedFractionAlignmentTop = 0

MsdDimStackedFractionType
MsdDimStackedFractionTypeDiagonal = 2
MsdDimStackedFractionTypeFromFont = 0
MsdDimStackedFractionTypeHorizontal = I

MsdDimStyleProp
msdDimStylePropBal1 AndChainAlignment = 101
msdDimStylePropBallAndChainChainTerminator = 1 0 2
msdDimStylePropBal1 AndChainChainType = 1 0 3
msdDimStylePropBallAndChainIsActive = 1 0 4
msdDimSty1 ePropBal1 AndChai nNoDockOnDimLi ne = 1 0 6
msdDimStylePropBal1 AndChainShowTextLeader = 1 0 5
msdDimSty1 ePropExtensi onLi neAngl eChordAl i gn = 2 1 3
msdDimStyl ePropExtensi onLi neCol or = 201
msdDimStylePropExtensionLineExtend = 202
msdDimStyl ePropExtensi onLi neJoi n = 203
msdDimSty1 ePropExtensi onLi neLeft = 204
msdDimStyl ePropExtensi onLi neLi neStyl e = 205
msdDimStylePropExtensionLineOffset = 206
msdDimStyl ePropExtensi onLi neOverrideCo1 or = 207
msdDimSty1 ePropExtensi onLi neOverrideLi neStyl e = 208
msdDimStyl ePropExtensi onLi neOverri deWei ght = 209
msdDimSty1 ePropExtensi onLi neRi ght = 2 1 0
msdDimStyl ePropExtensi onLi neShowAny = 211
msdDimSty1 ePropExtensi onLi neWei ght = 2 1 2
msdDimStylePropGenera1 Alignment = 3 0 1
msdDimStylePropGenera1 CenterMarkSize = 302
msdDimStylePropGenera1 Color = 303
msdDimStylePropGenera1 Dimensionscale = 304
msdDimStyl ePropGenera1 DimStyl eDescri pti on = 305
msdDimStylePropGenera1 DimStyleName = 306
msdDimStylePropGeneralFont = 307
I The Enumeration List I 255

msdDimStyl ePropGenera1 I g n o r e L e v e l Symbol ogy = 308


msdDimStyl ePropGenera1 L i n e S t y l e = 309
msdDimStyl ePropGenera1 O v e r r i d e C o l o r = 310
msdDimStyl ePropGenera1 O v e r r i d e L i n e S t y l e = 311
msdDimStylePropGeneralOverrideWeight = 312
msdDimStyl ePropGenera1 Radi a 1 Mode = 313
msdDimStyl ePropGenera1 Re1 a t i v e D i m L i n e = 314
m s d D i m S t y l e P r o p G e n e r a l S h o w C e n t e r M a r k = 315
msdDimStylePropGeneralStacked = 316
msdDimStylePropGeneralStackOffset = 317
msdDimStyl ePropGenera1 W e i g h t = 318
msdDimStylePropInva1 i d = 0
msdDimStyl ePropMLNoteE1 bowLength = 108
msdDimStylePropMLNoteFrameType = 401
m s d D i m S t y l e P r o p M L N o t e H o r A t t a c h m e n t = 407
msdDimStylePropMLNoteJustification = 402
m s d D i m S t y l e P r o p M L N o t e L e a d e r T y p e = 405
m s d D i m S t y l e P r o p M L N o t e L e f t M a r g i n = 410
m s d D i m S t y l e P r o p M L N o t e L o w e r M a r g i n = 411
m s d D i m S t y l e P r o p M L N o t e S h o w L e a d e r = 403
m s d D i m S t y l e P r o p M L N o t e T e x t R o t a t i o n = 406
m s d D i m S t y l e P r o p M L N o t e V e r L e f t A t t a c h m e n t = 408
m s d D i m S t y l e P r o p M L N o t e V e r R i g h t A t t a c h m e n t = 409
m s d D i m S t y l e P r o p M L N o t e V e r t i c a 1 J u s t i f i c a t i o n = 404
msdDimStylePropPlacementAnnotationScale = 507
msdDimStylePropPlacementCompatibleV3 = 501
msdDimStyl ePropPl acementLeve1 = 502
msdDimSty1 e P r o p P l acementNotUseMode1 A n n o t a t i o n S c a l e = 506
msdDimStyl ePropPl a c e m e n t o v e r r i d e L e v e l = 503
msdDimStyl ePropPl a c e m e n t T e x t P o s i t i o n = 504
msdDimStylePropPlacementUseReferenceScale = 505
msdDimStylePropSymbo1 D i a m e t e r c h a r 601 =

msdDimStylePropSymbo1 D i a m e t e r F o n t 602 =

msdDimStylePropSymbolDiameterType = 603
msdDimStylePropSymbo1 L o w e r P r e f i x C h a r = 604
msdDimStylePropSymbo1 L o w e r S u f f i x C h a r = 605
256 I Chapter 12: The Microstation Object Model - Enums I
msdDimStylePropSymbolMainPrefixChar = 606
msdDimSty1 ePropSymbo1 Mai nSuffixChar = 607
msdDimStyl ePropSymbo1 P1 usMi nusChar = 608
msdDimSty1 ePropSymbo1 P1 usMi nusType = 609
msdDimStyl ePropSymbo1 Prefix = 610
msdDimStylePropSymbolPrefixCellName = 611
msdDimStyl ePropSymbo1 Prefixchar = 612
msdDimSty1 ePropSymbo1 Prefi xFont = 613
msdDimStylePropSymbo1PrefixType = 614
msdDimStylePropSymbo1Suffix = 615
msdDimStylePropSymbo1Suffixcell Name = 616
msdDimStylePropSymbolSuffixChar = 617
msdDimStyl ePropSymbo1 Suffi xFont = 618
msdDimSty1 ePropSymbo1 Suffi xType = 619
msdDimStyl ePropSymbo1 To1 Prefixchar = 620
msdDimSty1 ePropSymbo1 To1 Suffixchar = 621
msdDimStylePropSymbolUpperPrefixChar = 622
msdDimStylePropSymbo1UpperSuffixChar = 623
msdDimStylePropTerminatorArrowCellName = 701
msdDimStylePropTerminatorArrowChar = 702
msdDimStylePropTerminatorArrowFont = 703
msdDimStylePropTerminatorArrowhead = 729
msdDimStylePropTerminatorArrowType = 704
msdDimStylePropTerminatorColor = 705
msdDimStylePropTerminatorDotCellName = 706
msdDimStylePropTerminatorDotChar = 707
msdDimStylePropTerminatorDotFont = 708
msdDimStylePropTerminatorDotType = 709
msdDimStylePropTerminatorFirst = 710
msdDimStylePropTerminatorHeight = 711
msdDimStylePropTerminatorJoint = 712
msdDimStylePropTerminatorLeft = 713
msdDimStylePropTerminatorLineStyle = 714
msdDimStylePropTerminatorMinLeader = 715
msdDimStylePropTerminatorMode = 716
msdDimStylePropTerminatorNoLineThruArrow = 717
I The Enumeration List I 257

m s d D i m S t y l e P r o p T e r m i n a t o r N o L neThruDot = 718
m s d D i m S t y l e P r o p T e r m i n a t o r N o L neThruOrigin = 719
m s d D i m S t y l e P r o p T e r m i n a t o r N o L neThruStroke = 720
msdDimStylePropTerminatorNote = 736
msdDimStylePropTerminatorNoteCel1 Name = 738
msdDimStylePropTerminatorNoteChar = 739
m s d D i m S t y l e P r o p T e r m i n a t o r N o t e F o n t = 740
msdDimStylePropTerminatorNoteType = 737
msdDimStylePropTerminatorOriginCellName = 721
m s d D i m S t y l e P r o p T e r m i n a t o r O r i g i n C h a r = 722
m s d D i m S t y l e P r o p T e r m i n a t o r O r i g i n F o n t = 723
msdDimStylePropTerminatorOriginType = 724
msdDimStylePropTerminatorOverrideColor = 725
msdDimStylePropTerminatorOverrideLineStyle = 726
m s d D i m S t y l e P r o p T e r m i n a t o r O v e r r i d e W e i g h t = 727
m s d D i m S t y l e P r o p T e r m i n a t o r R i g h t = 728
msdDimStylePropTerminatorStrokeCellName = 730
m s d D i m S t y l e P r o p T e r m i n a t o r S t r o k e C h a r = 731
m s d D i m S t y l e P r o p T e r m i n a t o r S t r o k e F o n t = 732
msdDimStylePropTerminatorStrokeType = 733
m s d D i m S t y l e P r o p T e r m i n a t o r W e i g h t = 734
msdDimStylePropTerminatorWidth = 735
msdDimStylePropTextArcLengthSymbo1 = 801
m s d D i m S t y l e P r o p T e x t A u t o L i f t = 802
msdDimStylePropTextCapsule = 804
msdDimStyl ePropTextCo1 or = 805
msdDimStylePropTextDecimalComma = 806
msdDimStylePropTextFont = 808
msdDimStylePropTextFrameType = 837
msdDimStylePropTextHeight = 809
msdDimStyl ePropTextHorizonta1 = 810
msdDimStylePropTextHorizontalMargin = 811
msdDimStylePropTextInlineTextLift = 838
msdDimStylePropTextJustification = 812
msdDimStylePropTextLeadingZero = 813
msdDimStylePropTextLocation = 835
258 I Chapter 12: The Microstation Object Model - Enums I
msdDimStyl ePropTextOmi tLeadi ngDel imi ter = 815
msdDimStylePropTextOverrideColor = 8 1 6
msdDimStylePropTextOverrideHeight = 8 1 7
msdDimStylePropTextOverrideStackedFractions = 833
msdDimStylePropTextOverrideUnderline = 8 3 4
msdDimStylePropTextOverrideWeight = 818
msdDimStylePropTextOverrideWidth = 8 1 9
msdDimStylePropTextSecLeadingZero = 8 2 0
msdDimStylePropTextShowSecondary = 8 2 1
msdDimStylePropTextStackedFractionAlignment = 8 2 9
msdDimStylePropTextStackedFractions = 8 3 0
msdDimStylePropTextStackedFractionScale = 8 3 2
msdDimStylePropTextStackedFractionType = 831
msdDimStylePropTextSuperscriptMode = 8 3 9
msdDimStylePropTextTextStyle = 8 2 7
msdDimStylePropTextTextStyleID = 8 2 8
msdDimStylePropTextUnderline = 8 2 2
msdDimStylePropTextVerticalMargin = 8 2 4
msdDimStylePropTextVerticalOpts = 8 3 6
msdDimStylePropTextWeight = 8 2 5
msdDimStylePropTextWidth = 8 2 6
msdDimStylePropToleranceAccuracy = 9 1 0
msdDimStylePropToleranceLowerValue = 9 0 1
msdDimStylePropToleranceMode = 9 0 2
msdDimStylePropToleranceSecAccuracy = 9 1 1
msdDimStylePropToleranceShow = 9 0 3
msdDimStylePropToleranceStackEqua1 = 9 0 4
msdDimSty1 ePropTol eranceTextHori zontal Margi n = 9 0 5
msdDimStylePropToleranceTextScale = 9 0 6
msdDimStylePropToleranceTextVerticalMargin = 9 0 7
msdDimStyl ePropTol eranceTextVerti cal Separation = 908
msdDimStylePropToleranceUpperValue = 9 0 9
msdDimStylePropValueAccuracy = 1 0 0 1
msdDimStylePropValueAltAccuracy = 1 0 0 2
msdDimStyl ePropVal ueAl tFormat = 1 0 6 7
msdDimStylePropValueAltIsActive = 1 0 0 3
I The Enumeration List I 259

m s d D i m S t y l e P r o p V a l u e A l t S e c A c c u r a c y = 1004
m s d D i m S t y l e P r o p V a l u e A l t S e c F o r m a t = 1069
m s d D i m S t y l e P r o p V a l u e A l t S e c I s A c t i ve = 1005
msdDimStylePropValueAltSecShowZeroMasterUnit = 1012
msdDimStylePropValueAltSecShowZeroSubUnit = 1081
msdDimStyl ePropVal ueAl tSecThresho1 d = 1013

msdDimStylePropValueAltSecThresholdComparison = 1071
msdDimStylePropValueAltShowZeroMasterUnit = 1020
msdDimStylePropValueAltShowZeroSubUnit = 1079
m s d D i m S t y l e P r o p V a l u e A l t T h r e s h o l d = 1021
m s d D i m S t y l e P r o p V a l u e A l t T h r e s h o l dCompari s o n = 1070
m s d D i m S t y l e P r o p V a l ueAngl e F o r m a t = 1023
msdDimStylePropValueAngleLeadingZero = 1024
m s d D i m S t y l e P r o p V a l ueAngl eMeasure = 1025
m s d D i m S t y l e P r o p V a l ueAngl e P r e c i s i o n = 1026
msdDimStylePropValueAngleTrailingZeros = 1027
msdDimStylePropValueDMSPrecisionMode = 1082
msdDimStylePropValueFormat = 1066
m s d D i m S t y l e P r o p V a l u e L a b e l L i n e F o r m a t = 1077
m s d D i m S t y l e P r o p V a l u e N o R e d u c e A l t F r a c t i o n = 1043
msdDimStylePropValueNoReduceAltSecFraction = 1062
m s d D i m S t y l e P r o p V a l u e N o R e d u c e F r a c t i o n = 1042
m s d D i m S t y l e P r o p V a l u e N o R e d u c e S e c F r a c t i on = 1061
m s d D i m S t y l e P r o p V a l u e N o R e d u c e T o l F r a c t i o n = 1044
m s d D i m S t y l e P r o p V a l ueNoReduceTo1 S e c F r a c t i on = 1063
m s d D i m S t y l e P r o p V a l ueOrdDatumVa1 ue = 1057
m s d D i m S t y l e P r o p V a l u e O r d D e c r e m e n t R e v e r s e = 1055
m s d D i m S t y l e P r o p V a l u e O r d F r e e L o c a t i o n = 1065
msdDimStylePropValueOrdUseDatumValue = 1056
m s d D i m S t y l e P r o p V a l ueRoundLSD = 1028
msdDimStylePropValueSecAccuracy = 1029
msdDimStylePropValueSecFormat = 1068
msdDimStylePropValueSecShowTrailingZeros = 1033
msdDimStylePropValueSecShowZeroMasterUnit = 1035
msdDimStylePropValueSecShowZeroSubUnit = 1080
msdDimStylePropValueSecUnitMaster = 1075
260 I Chapter 12: The Microstation Object Model - Enums I
msdDimStylePropValueSecUnitSub = 1076
msdDimStylePropValueShowTrailingZeros = 1039
msdDimStylePropValueShowZeroMasterUnit = 1041
msdDimStylePropValueShowZeroSubUnit = 1078
msdDimStylePropValueSuperscriptLSD = 1045
msdDimStylePropValueThousandsOpts = 1072
msdDimStylePropValueUnit = 1048
msdDimStylePropValueUnitLabelMaster = 1049
msdDimStylePropValueUnitLabe1 SecMaster = 1050
msdDimStylePropValueUnitLabelSecSub = 1051
msdDimStyl ePropVal ueUni tLabel Sub = 1052
msdDimStylePropValueUnitMaster = 1073
msdDimStylePropValueUnitSec = 1053
msdDimStylePropValueUnitSub = 1074
msdDimStylePropValueUseWorkingUnits = 1054

MsdDimSuperscriptMode
MsdDimSuperScriptModeFromFont = 0
MsdDimSuperScriptModeGenerated = 1

MsdDimSymbolType
msdDimSymbol TypeCell = 2
msdDimSymbolTypeCharacter = 1
msdDimSymbolTypeDefau1 t = 0

MsdDimTerminatorArrowhead
msdDimTerminatorArrowheadClosed = 1
msdDimTerminatorArrowheadFilled = 2
msdDimTerminatorArrowheadOpen = 0

MsdDimTerminatorMode
msdDimTerminatorModeAuto = 0
msdDimTerminatorModeInside = 2
msdDimTerminatorModeOutside = 3
msdDimTerminatorModeReversed = 1

MsdDimTerminatorType
msdDimTerminatorTypeArrow = 1
I The Enumeration List I 261

msdDimTermi n a t o r T y p e C i r c l e = 3
msdDimTerminatorTypeDot = 4
msdDimTerminatorTypeNone = 0
msdDimTerminatorTypeNote = 5
msdDimTerminatorTypeOrigin = 3
msdDimTerminatorTypeStroke = 2

MsdDimTextField
msdDimTextFie1dLowerLimi t = 1
msdDi mText F i e l dMai n = 0
msdDi mText F i e l dMi n u s = 2
m s d D i m T e x t F i e 1 dP1 us = 1
msdDimTextFie1dUpperLimi t = 0

MsdDimTextFormat
MsdDimTextFormatMU = 0
MsdDimTextFormatMU-dash-SU = 4
MsdDimTextFormatMU-Label = 1
Msd D i mText Forma tMU-La be1 -da s h-SU-La be1 = 6
MsdDimText FormatMU-Label-SU-Label = 5

MsdDimTextFormatSU = 2
MsdDimTextFormatSU-Label = 3

MsdDimTextFrameType
MsdDimTextFrameTypeBox = 1
MsdDimTextFrameTypeCapsule = 2
MsdDimTextFrameTypeNone = 0

MsdDimTextJustification
msdDimTextJustificationCenter = 2
msdDi m T e x t J u s t i f ic a t i on L e f t = 1
msdDi m T e x t J u s t i f ic a t i o n R i g h t = 3

MsdDimTextLocation
MsdDimTextLocationAbove = 1
MsdDimTextLocationInline = 0
MsdDimTextLocationOutside = 2
MsdDimTextLocationTopLeft = 3
262 I Chapter 12: The Microstation Object Model - Enums I
MsdDimTextOrientation
MsdDimTextOri entati onAl i gned = 0
MsdDimTextOri entati onHori zontal = 1
MsdDimThousandsOpts
MsdDimThousandsOptsComma = 2
MsdDimThousandsOptsNone = 0
MsdDimThousandsOptsSpace = 1

MsdDimToleranceType
MsdDimTol eranceTypeLimi t = 1
MsdDimTol eranceTypeP1 usMi nus = 0

MsdDimType
msdDimTypeAng1 eAxi s = 10
msdDimTypeAng1 eAxi sX = 50
msdDimTypeAng1 eAxi sY = 51
msdDimTypeAng1 eLi nes = 9
msdDimTypeAng1 eLocati on = 7
msdDimTypeAng1 eSi z e = 5
msdDimTypeArcLocation = 8
msdDimTypeArcSi z e = 6
msdDimTypeCenter = 19
msdDimTypeCustomLinear = 1 5
msdDimTypeDiameter = 1 2
msdDimTypeDiameterExtended = 18
msdDimTypeDiameterPara = 1 3
msdDimTypeDiameterPerp = 1 4
msdDimTypeLabe1 Line = 52
msdDimTypeLocateSi ngl e = 3
msdDimTypeLocateStacked = 4
msdDimTypeNone = 0
msdDimTypeNote = 53
msdDimTypeOrdinate = 1 6
msdDimTypeRadi us = 11
msdDimTypeRadiusExtended = 17
msdDimTypeSizeArrow = 1
I The Enumeration List I 263

msdDimTypeSizeStroke = 2
msdDimTypeUseActive = - 1

MsdDimValueAngleFormat
msdDimVal ueAngl eFormatCentesima1 = 2
msdDimVa1 ueAngl eFormatDegMinSec = 1
msdDimVal ueAngl eFormatDegrees = 0
msdDimVa1 ueAngl eFormatRadi ans = 3

MsdDimValueAnglePrecision
msdDimVal u e A n g l e P r e c i s i o n l P 1 ace = 1
msdDimVa1 u e A n g l e P r e c i s i o n Z P 1 ace = 2
msdDimVal u e A n g l e P r e c i s i o n 3 P l ace = 3
msdDimVa1 u e A n g l e P r e c i s i o n 4 P l ace = 4
msdDimVal u e A n g l e P r e c i s i o n 5 P l ace = 5
msdDimVa1 u e A n g l e P r e c i s i o n G P 1 ace = 6
msdDimVal u e A n g l e P r e c i s i o n W h o l e = 0

MsdDimVerticalTextOptions
MsdDimVerti c a l TextOptionsAl ways = 1
MsdDimVertical TextOptionsNever = 0
MsdDimVertical TextOptionsNoFi t = 2

MsdDrawingMode
msdDrawingModeErase = 1
msdDrawingModeHilite = 2
msdDrawi ngModeNorma1 = 0
msdDrawingModeTemporary = 3
msdDrawingModeTemporaryErase = 4
msdDrawingModeXor = 6

MsdElementCachePurpose
msdElementCachePurposeContro1 = 2
msdEl ementCachePurposeGraphi c a l = 4
msdElementCachePurposeNonMode1 = 1

MsdElementclass
msdElementClassConstruction = 2
264 I Chapter 12: The Microstation Object Model - Enums I
msdEl ementCl asscontructi onRul e = 6
msdEl ementCl assDimensi on = 3
msdEl ementCl assLinearPatterned = 5
msdElementClassPatternComponent = 1
msdEl ementCl assprimary = 0
msdEl ementCl assPrimaryRul e = 4

MsdElementSubtype
msdEl ementSubtypeApp1 i cati onEl ement = 20
msdElementSubtypeAuxiliaryCoordinateSystem = 3
msdElementSubtypeNone = -1
msdElementSubtypeUpdateSequenceElement = 33

MsdElementType
msdEl ementType44 = 44
msdElementTypeArc = 1 6
msdEl ementTypeBsp1 i neBoundary = 25
msdElementTypeBsplineCurve = 27
msdEl ementTypeBsp1 i neKnot = 26
msdEl ementTypeBsp1 i nePol e = 21
msdElementTypeBsplineSurface = 2 4
msdEl ementTypeBsp1 i neWei ght = 28
msdEl ementTypeCel1 Header = 2
msdEl ementTypeCel1 Li braryHeader = 1
msdEl ementTypeComp1 exshape = 1 4
msdEl ementTypeComp1 exStri ng = 1 2
msdElementTypeCone = 23
msdEl ementTypeConi c = 1 3
msdElementTypeCurve = 11
msdEl ementTypeDesi gnFi 1 eHeader = 9
msdElementTypeDgnStoreComponent = 38
msdElementTypeDgnStoreHeader = 39
msdEl ementTypeDi gSetData = 8
msdEl ementTypeDimensi on = 33
msdEl ementTypeEl1 i pse = 1 5
msdElementTypeGroupData = 5
msdEl ementTypeLeve1 Mask = 99
4
0-l
r
.
II co
4 0 r
.
4 c,o 0
N 4 S 4 C O N m
m o 0 a, 0 N 4
0 4 II 4 S II 4 r.m
4 4 CO 0 0 d C O
II c, CO 0-l Q c, II 4 4
II 4 S II E S N N
0 m co a, II r
. II 0 a, a, I r .
m 4 c, Lo co S L N d CO 0 E u d
c, m 0 0 a, N c, 0-l a, a, 1 .r u) II 4
d m II n 4 II co Q u S II 0 0 0 L 0-l r
. N
n L m E m II
a, II S S m L 0-l L I
r
. a,
II c, II
II Lo
.r C O Q m s
4 aJ0-l s z o
u 0 u .r
II 0 II L N c ,
z m a , m
L L c, c, c, c,
E .r Lo v, Lo v, Lo cc Lc m m
a, a, n c, c , 3 3 0 -
c, c, Q Q O , X X a J a , S O
m m m o m m m m m a, a, 1 C m m m a, a, .r .r a, .r
z E
a, a,
z a a a a a a a a v, v,
a J a J a , a, a, a, a, a, a, a, a,
+ + + + + > >
a J a J a , a, a J a J a ,
L >
aJv,
Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q L c v ,
h h h h h h h h h h h h h h h h h h h h a J w
+
Q
+ Q
+ + + + + + + + + + +
4 3 4 3 4 3 Q Q Q Q Q Q Q Q
+ + + + + + +
4 3 4 3 4 3 Q 4 3 4 3 4 3
c f 0
- 0 0
s s s s S S s s s s s s s S S S S S S S S s s s s s s S s s s m a
a J w a J w aJ a, a J w a J w a J w a J a, aJ a, aJ a, aJ a, aJ W a J W a J W a J a, a J w a J L L
E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E 0 0
a J w a J w aJ a, a J w a J w a J w a J a, aJ a, aJ a, aJ a, aJ W a J W a J W a J a, a J w a J L L
7 - 7 7 7 7 7 - 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 L L
w w w w W W w w w w w w w W W W W W W W W w w w w w w W w w w w w
-0-0-0-0 -0 -0 -0-0-0-0 -0-0-0 -0 -0 -0 -0 -0 -0 -0 -0 -0-0-0 -0-0-0 -0 -0-0-0 -0-0
C n c n c n v , v, v, C n c n c n v , C n c n v , v, v, v, v, v, v, v, v, C n c n v , C n c n v , v, C n c n v , W v ,
E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E
266 I Chapter 12: The Microstation Object Model - Enums I
msdErrorAcsNotFound = -2147220744
msdErrorAcsReplaced = -2147220745
msdErrorAddressNotKnown = -2147220784
msdErrorAddressNotValid = -2147220779
msdErrorAlreadyExists = -2147218310
msdErrorAlreadyInUse = -2147220804
msdErrorAlreadyOpen = -2147218312
msdErrorBadBSplineElement = -2147217996
msdErrorBadCharacterConstant = -2147220794
msdErrorBadContinuity = -2147217986
msdErrorBadElement = -2147218399
msdErrorBadFile = -2147218304
msdErrorBadFloat = -2147220796
msdErrorBadFormat = -2147218309
msdErrorBadHexNumber = -2147220799
msdErrorBadIndex = -2147218370
msdErrorBadKnots = -2147217991
msdErrorBadLineWeights = -2147217990
msdErrorBadModelId = -2147218334
m s d E r r o r B a d M o d e l R e f e r e n c e = -2147218397
msdErrorBadName = -2147218316
msdErrorBadNumber = -2147220800
msdErrorBadOcta1 = -2147220797
msdErrorBadOrder = -2147217994
msdErrorBadParameter = -2147217995
msdErrorBadPeriodicity = -2147217993
msdErrorBadPoles = -2147217992
msdErrorBadRasterFormat = -2147218350
msdErrorBadResourceType = -2147220772
msdErrorBadScanList = -2147218389
msdErrorBadSpi ral Definition = -2147217989
msdErrorBadString = -2147220795
msdErrorBadType = -2147220803
msdErrorBadVersion = -2147218308
msdErrorBadWordsToFollow = -2147218311
msdErrorCacheInUse = -2147218318
I The Enumeration List I 267

msdErrorCacheLoadError = -2147218291
msdErrorCacheNotEnabled = -2147218320
msdErrorCacheNotFilled = -2147218288
msdErrorCacheNotFound = -2147218317
msdErrorCannotCreateFile = - 2 1 4 7 2 1 8 3 2 9
msdErrorCannotDereference = - 2 1 4 7 2 2 0 7 8 7
msdErrorCannotImportSeed = - 2 1 4 7 2 1 8 2 9 2
msdErrorCannotOpenFile = -2147218391
msdErrorCannotOpenSeed = -2147218303
msdErrorCannotSaveFile = -2147218328
m s d E r r o r C e l l E x i s t s = -2147218372
msdErrorCel1 L i b r a r y I s 2 d = -2147218365
msdErrorCellNotFound = -2147218373
msdErrorCellTooLarge = -2147218369
msdErrorCircularDependency = - 2 1 4 7 2 1 9 6 0 4
msdErrorCommandReceived = - 2 1 4 7 2 2 0 7 0 4
msdErrorComplexHeaderRequired = - 2 1 4 7 2 1 8 3 8 7
msdErrorCompressionError = - 2 1 4 7 2 1 8 2 9 6
msdErrorCopyError = -2147218289
msdErrorDiskFul1 = -2147218395
msdErrorDivideByZero = -2147220780
msdErrorDup1 i c a t e L o g i c a l = - 2 1 4 7 2 2 0 7 6 6
msdErrorDuplicateTaskId = -2147218353
m s d E r r o r E l e m e n t F i l l e d = -2147220756
msdErrorElementFrozen = -2147218359
msdErrorElementNotFilled = - 2 1 4 7 2 2 0 7 5 5
msdErrorElementNotFound = -2147218323
msdErrorElementNotPlanar = - 2 1 4 7 2 2 0 7 5 3
msdErrorElementTooLarge = -2147220754
msdErrorEndOfFile = -2147218390
msdErrorException = -2147219504
m s d E r r o r F i l e E x i s t s = -2147218326
msdErrorFileNotFound = -2147218338
msdErrorHasChanges = -2147218298
m s d E r r o r I d E x i s t s = -2147218321
msdErrorIdNotFound = -2147218322
268 I Chapter 12: The Microstation Object Model - Enums I
msdErrorIllegalCharacter = -2147220793
msdErrorInsufficientInformation = -2147218401
msdErrorInsufficientMemory = -2147218388
msdErrorIntegralNeeded = -2147220777
msdErrorInvalidACSType = -2147220770
msdErrorInvalidButton = -2147220769
msdErrorInvalidCel1 = -2147218371
msdErrorInvalidClip = -2147220761
msdErrorInvalidForFloat = -2147220781
msdErrorInvalidForFunction = -2147220771
msdErrorInvalidForStructure = -2147220782
msdErrorInvalidForType = -2147220778
msdErrorInva1 idLi brary = -2147218368
msdErrorInvalidMaterOrigin = -2147220763
msdErrorInvalidOperationForNested = -2147218302
msdErrorInvalidOperationForNonNested = -2147218301
msdErrorInvalidPatternSpace = -2147220760
msdErrorInvalidReference = -2147220762
msdErrorInvalidReferenceOrigin = -2147220764
msdErrorInvalidSymbo1 = -2147220789
msdErrorLinkageNotFound = -2147218344
msdErrorLoadingInterface = -2147218297
m s d E r r o r M o d e l e r N o t L o a d e d = -2147219703
msdErrorMode1 IdExists = -2147218332
msdErrorModelNameExists = -2147218333
msdErrorMode1 NotEmpty = -2147218342
msdErrorModifyComplex = -2147218392
msdErrorNameNotUnique = -2147218343
msdErrorNameTooLong = -2147218335
msdErrorNeedExponent = -2147220798
msdErrorNeedInteger = -2147220802
msdErrorNoAcsDefined = -2147220746
msdErrorNoBounds = -2147218001
msdErrorNoBSplineHeader = -2147217999
msdErrorNoCel1 Library = -2147218375
msdErrorNoClipVolume = -2147218336
IThe Enumeration List I 269

msdErrorNoFence = -2147218337
msdErrorNoGraphicGroup = -2147220742
msdErrorNoKnots = -2147218003
msdErrorNoLevelMask = -2147220740
msdErrorNoLineWeights = -2147218002
msdErrorNoMatch = -2147218381
msdErrorNoMode1 = -2147218299
msdErrorNoMode1 Information = -2147218331
msdErrorNonClosedElement = -2147220757
msdErrorNonClosedPatternElement = -2147220759
msdErrorNonCoplanarShapes = -2147220750
msdErrorNonSolidPatternElement = -2147220758
msdErrorNoNumberBounds = -2147218000
msdErrorNoOffsetIntersection = -2147217987
msdErrorNoParentMode1 = -2147218330
msdErrorNoPoles = -2147218004
msdErrorNoReferenceSlots = -2147220747
msdErrorNoselectionSet = -2147220748
msdErrorNoSuchMode1 = -2147218294
msdErrorNoSymbo1 = -2147220791
msdErrorNotDesignFIle = -2147220768
msdErrorNotDirectAttachment = -2147220739
msdErrorNotFunction = -2147220775
msdErrorNotLoaded = -2147218300
msdErrorNotLocked = -2147218293
msdErrorNotMember = -2147220785
msdErrorNotOpen = -2147218315
msdErrorNotSingleView = -2147220765
msdErrorNotStructure = -2147220786
msdErrorNotSupported = -2147218348
msdErrorNotValidExpression = -2147220776
msdErrorNu1 lSol ution = -2147220752
msdErrorOldMaterialTable = -2147220749
msdErrorOperationCanceled = -2147218306
msdErrorParasolidError = -2147219703
msdErrorReadOnly = -2147218396
270 I Chapter 12: The Microstation Object Model - Enums I
m s d E r r o r R e c u r s e L i m i t = -2147217985
msdErrorRenameError = -2147218290
m s d E r r o r R e q u i r e s 3 d F i l e = -2147218400
m s d E r r o r R e s o u r c e N o t F o u n d = -2147218376
m s d E r r o r S h a r i n g V i o l a t i o n = -2147218314
m s d E r r o r S t r u c t u r e N e e d e d = -2147220801
msdErrorSymbo1 N o t R e s o l v e d = - 2 1 4 7 2 1 9 7 0 4
m s d E r r o r S y n t a x E r r o r = -2147220790
m s d E r r o r S y s t e m E r r o r = -2147218363
m s d E r r o r T a g B a d A s s o c i a t i o n = -2147220096
m s d E r r o r T a g B a d R e p o r t F i l e = -2147220098
m s d E r r o r T a g B a d R e p o r t K e y w o r d = -2147220097
msdErrorTagNameTooLong = - 2 1 4 7 2 2 0 0 9 2
m s d E r r o r T a g N o T a r g e t = -2147220095
m s d E r r o r T a g N o t F o u n d = -2147220093
msdErrorTagNotInSet = -2147220101
m s d E r r o r T a g P r e v i o u s l y D e f i n e d = -2147220094
msdErrorTagSetNameLong = -2147220103
msdErrorTagSetNotFound = -2147220102
m s d E r r o r T a g S e t P r e v i o u s l y D e f i n e d = -2147220100
m s d E r r o r T a g S e t T o o B i g = -2147220099
msdErrorTagUndefinedType = -2147220104
msdErrorTimeout = -2147218362
m s d E r r o r T o o C o m p l e x = -2147220783
m s d E r r o r T o o F e w A r g u m e n t s = -2147220773
msdErrorTooFewPoles = -2147217998
msdErrorTooManyArguments = - 2 1 4 7 2 2 0 7 7 4
msdErrorTooManyKnots = -2147217988
msdErrorTooManyOpenFiles = -2147218307
m s d E r r o r T o o M a n y P o l e s = -2147217997
msdErrorTooManySurfaceElements = -2147218346
msdErrorTypesIncompatible = - 2 1 4 7 2 2 0 7 8 8
msdErrorUnboundedSolution = -2147220751
m s d E r r o r U n k n o w n E r r o r = -2147218305
m s d E r r o r U n k n o w n F o r m a t = -2147218295
msdErrorUnsupported = -2147220792
I The Enumeration List I 271

msdErrorUserCanceledAction = -2147218382
msdErrorV7CellLibrary = -2147218327
msdErrorViewGroupNotFound = -2147220741
msdErrorViewNotDisplayed = -2147218374
msdErrorViewNotFound = -2147220743
msdErrorWriteFailed = -2147218393
msdErrorWriteInhibited = -2147218394
msdErrorWrongElementID = -2147218319

MsdFileAccessMode
msdFileAccessModeRead = 1
msdFileAccessModeReadWrite = 3

MsdFillMode
msdFi 1 1 ModeFi 1 1 ed = 1
msdFi 1 1 ModeNotFi 1 1 ed = 0
msdFi 1 1 ModeOutl i ned = 2
msdFillModeUseActive = - 1

MsdFontType
msdFontTypeMicroStation = 0
msdFontTypeSHX = 1
msdFontTypeUnknown = 3
msdFontTypeWindowsTrueType = 2

MsdGeoReferenceSisterFileType
msdGeoReferenceSisterFileTypeHgr = 1
msdGeoReferenceSisterFileTypeNone = 0
msdGeoReferenceSisterFileTypeTwf = 2

MsdGlobalLineStyleScale
msdGl obal Li neStyl eScal eBoth = 3
msdGl obal Li neStyl eScal eMaster = 0
msdGl obal Li neStyl eScal eNone = 1
msdGl obal Li neStyl eScal eReference = 2

MsdLevelChangeType
msdLevelChangeAfterChangeActive = 9
272 I Chapter 12: The Microstation Object Model - Enums I
msdLevelChangeAfterCreate = 2
msdLevel ChangeAfterDel ete = 3
msdLevelChangeBeforeChangeActive = 17
msdLevel ChangeBeforeDel ete = 18
msdLevelChangeChangeAttribute = 8
msdLevelChangeChangeCode = 5
msdLevel ChangeChangeDi spl ay = 7
msdLevelChangeChangeName = 4
msdLevelChangeChangeParent = 6
msdLevel ChangeTabl eRedo = 15
msdLevel ChangeTabl eUndo = 14

MsdLevelElementAccess
msdLevel El ementAccessAl1 = 0
msdLevel El ementAccessLocked = 1
msdLevel El ementAccessReadOnly = 2
msdLevel El ementAccessVi ewOnly = 3
MsdLimits
msdLimitsMaxVertices = 5000
msdLimi tsMaxVi ews = 8
MsdMeasurementBase
msdMeasurementBaseDegree = 2
msdMeasurementBaseMeter = 1
msdMeasurementBaseNone = 0
MsdMeasurementSystem
msdMeasurementSystemEnglish = 1
msdMeasurementSystemMetric = 2
msdMeasurementSystemUndefined = 0

MsdMem berTraverseType
msdMemberTraverseCopy = 2
msdMemberTraverseDirectMembers = 4
msdMemberTraverseEnumerate = 3
msdMemberTraverseManipulate = 1
msdMemberTraverseSimple = 0
I The Enumeration List I 273

MsdMessageCenterPriority
m s d M e s s a g e C e n t e r P r i o r i t y D e b u g = 13
m s d M e s s a g e C e n t e r P r i o r i t y E r r o r = 10
m s d M e s s a g e C e n t e r P r i o r i t y I n f o = 12
m s d M e s s a g e C e n t e r P r i o r i t y N o n e = 14
m s d M e s s a g e C e n t e r P r i o r i t y W a r n i n g = 11

MsdModelChangeType
mdl Model C h a n g e A c t i ve = 5
mdlModel C h a n g e B e f o r e A c t i v e = 11
mdlModelChangeBeforeCreate = 15
mdl Model ChangeBeforeDel e t e = 6
mdlModelChangeBeforeName = 12
mdlModelChangeBeforeProperties = 14
mdlModel C h a n g e B e f o r e S e t t i n g s = 13
mdlModelChangeBeforeUnCreate = 9
mdlModelChangeBeforeUnDelete = 16
mdlModelChangeCreate = 1
mdl Model ChangeDel e t e = 2
mdlModelChangeName = 10
mdlModelChangePropagateAnnotationScale = 17
mdl Model C h a n g e p r o p e r t i es = 3
mdlModelChangeSettings = 4
mdlModelChangeUnCreate = 7
mdl Model ChangeUnDel e t e = 8

MsdModelType
msdModel T y p e D e f a u l t = - 1
msdModelTypeExtraction = 2
msdModel TypeNorma1 = 0
msdModel T y p e S h e e t = 1

MsdNestoverrides
msdNestOverridesAlways = 1
msdNestOverridesAsRequired = 0
msdNestOverridesNever = 2
274 I Chapter 12: The Microstation Object Model - Enums I
MsdNewLevelDisplay
msdNewLeve1 D i s p l a y A l ways = 1
msdNewLeve1 D i s p l a y F r o m C o n f i g = 0
msdNewLeve1 D i s p l a y N e v e r = 2

MsdRasterBlockType
msdRasterB1 ockTypeImage = 4
msdRasterBlockTypeLine = 1
msdRasterBlockTypeStrip = 3
msdRasterB1 o c k T y p e T i 1 e = 2

MsdRasterDisplayOrderCommand
msdRasterDisplayOrderCommandBackward = 3
msdRasterDisplayOrderCommandForward = 2
msdRasterDisplayOrderCommandToBack = 1
msdRasterDisplayOrderCommandToFront = 0

MsdRasterDisplayPriorityPlane
m s d R a s t e r D i s p l a y P r i o r i t y P l aneBack = 1
msdRasterDi s p l a y P r i o r i tyPl aneFront = 3
msdRasterDi s p l a y P r i o r i tyPl aneVector = 2

MsdRasterModificationType
m s d R a s t e r M o d i f i c a t i onTypecC1 ip B o u n d a r y = 5
m s d R a s t e r M o d i f i c a t i onTypecC1 ipMask = 4
msdRasterModificationType-ExtendedInformation = 0
msdRasterModificationType-GeoReferenceInformation = 1
msdRasterModificationType-RasterInformation = 3
m s d R a s t e r M o d i f i c a t i onType-Re1 oad = 6
m s d R a s t e r M o d i f i c a t i onType-Renderi n g I n f o r m a t i on = 2

MsdRasterworldFile
msdRasterWor1 d F i 1 eHgr = 1
msdRasterWor1 d F i 1 eNone = 0
msdRasterWor1 d F i 1 eWorl d F i 1 e = 2

MsdReferencesystem
msdReferenceSystemDgn = 2
I The Enumeration List I 275

msdReferenceSystemRaster = 1

MsdRenderingMode
msdRenderingModeConstantShade = 5
msdRenderingModeCrossSection = 1
msdRenderingModeHiddenLine = 3
msdRenderingModeParticleTrace = 11
m s d R e n d e r i ngModePhong = 7
m s d R e n d e r i n g M o d e R a d i o s i t y = 10
m s d R e n d e r i ngModeRayTrace = 8
msdRenderingModeRenderWireFrame = 9
msdRenderingModeSmoothShade = 6
m s d R e n d e r i ngModeSol i d F i 11 = 4
msdRenderingModeWireFrame = 0
m s d R e n d e r i ngModeWi reMesh = 2

MsdStandardsCheckerReplaceChoice
msdStandardsCheckerReplaceChoiceAbort = 4
msdStandardsCheckerReplaceChoiceFix = 1
msdStandardsCheckerReplaceChoiceMarkIgnored = 2
msdStandardsCheckerReplaceChoiceMarkNotIgnored = 3
msdStandardsCheckerReplaceChoiceSkip = 0

MsdStandardsCheckerReplaceoptions
msdStandardsCheckerReplaceOptionCanFix = 2
msdStandardsCheckerReplaceOptionCanIgnore = 1

MsdStatusBarArea
msdStatusBarAreaLeft = 16
msdStatusBarAreaMiddle = 15

MsdTagType
msdTagTypeBi n a r y = 5
msdTagTypeCharacter = 1
msdTagTypeDoub1 e = 4
msdTagTypeLongInteger = 3
msdTagTypeShortInteger = 2
276 I Chapter 12: The Microstation Object Model - Enums I

MsdTangentElementOutputType
msdTangentArcs = 1
msdTangentCi r c l es = 0
msdTangentTri angl es = 2

MsdTangentlnterpolationType
msdTangentFromCi r c l e F i t = 1
msdTangentFromCubicFit = 2
msdTangentFromCurve = 0

MsdTextDirection
msdTextDi r e c t i onHori z o n t a l = 0
msdTextDi r e c t i onRi g h t T o L e f t = 8
msdTextDi r e c t i o n V e r t i c a l = 4
m s d T e x t D i r e c t i o n V e r t i c a l Mu1 t i L i n e R i g h t T o L e f t = 2

MsdTextJustification
msdTextJustificationCenterBottom = 8
msdTextJustificationCenterCenter = 7
msdTextJustificationCenterTop = 6
msdTextJustificationLeftBottom = 2
msdTextJustificationLeftCenter = 1
m s d T e x t J u s t i f ic a t i onLeftTop = 0
msdTextJustificationRightBottom = 14
msdTextJustificationRightCenter = 13
msdTextJustificationRightTop = 12

MsdTextNodeLineSpacingType
msdTextNodeLineSpacingTypeAtLeast = 3
msdTextNodeLineSpacingTypeAutomatic = 1
msdTextNodeLineSpacingTypeExact = 0
msdTextNodeLineSpacingTypeExactFromLineTop = 2

MsdV7Action
msdV7ActionAskUser = 0
msdV7ActionUpgradeToV8 = 1
msdV7ActionWorkmode = 3
I Review I 277

MsdViews
msdViewl = 1
msdView2 = 2
msdView3 = 4
msdView4 = 8
msdView5 = 16
msdView6 = 32
msdView7 = 64
msdView8 = 128
msdViewAll = 255
msdViewNone = 0

MsdXDatumType
msdXDatumTypeBinaryData = 1004
m s d X D a t u m T y p e C o n t r o l S t r i n g = 1002
msdXDatumTypeDatabaseHandle = 1005
msdXDatumTypeDistance = 1041
msdXDatumTypeIntl6 = 1070
msdXDatumTypeInt32 = 1071
msdXDatumTypeLeve1 = 1003
msdXDatumTypePoint = 1010
msdXDatumTypeRea1 = 1040
m s d X D a t u m T y p e S c a l e F a c t o r = 1042
msdXDatumTypeString = 1000
msdXDatumTypeUnsupported = 0
m s d X D a t u m T y p e W o r l d D i r e c t i o n = 1013
msdXDatumTypeWorldSpaceDisplacement = 1012
msdXDatumTypeWorldSpacePosition = 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.
13 The Microstation Object
Model - Types

Thus far we have introduced and discussed concepts such as variables,


objects, properties, and methods. We are now going to discuss types.
A type is used like a variable but is similar to an object because it holds
multiple elements. The best way to demonstrate this is by looking at a
type we will use extensively in our Microstation VBA programming.

Type P o i n t 3 d
X As D o u b l e
Y As D o u b l e
Z As D o u b l e
End T y p e

The Point3d type has three members: X (which is a Double), Y (which is


a Double) and Z (which is a Double).

Sub T e s t P o i n t 3 d ( 1
D i m S t a r t p o i n t As P o i n t 3 d
D i m E n d p o i n t As P o i n t 3 d
D i m MyLine As LineElement
StartP0int.X = 1.5
StartP0int.Y = 2.5

279
280 I Chapter 13: The Microstation Object Model - Types I
StartP0int.Z = 3.5
EndP0int.X = 4
EndP0int.Y = 0
EndP0int.Z = 0
= CreateLineElement2(Nothing, S t a r t p o i n t , E n d p o i n t )
S e t MyLine
ActiveModelReference.AddElement M y L i n e
End Sub

We declare two variables with a type of Point3d: We assign coordinate


values to the X, Y, and Z elements of these variables. They are then used
with the CreateLineElement2 method. Here is the declaration for
CreateLineElement2:

S u b C r e a t e L i n e E l e m e n t 2 ( T e m p l a t e As E l e m e n t , S t a r t p o i n t As P o i n t 3 d ,
E n d p o i n t As P o i n t 3 d ) as L i n e E l e m e n t

Notice how this method is asking for two Point3d Types - one for the
Start Point and the other for the End Point.
Here is a list of the types we have available to us in Microstation VBA:

T y p e MsdACSType
J u s t i f i c a t i o n As M s d D a t a E n t r y R e g i o n J u s t i f i c a t i on
L e n g t h As L o n g
S t a r t P o s i t i o n As L o n g
End T y p e

T y p e MsdACSType
H i g h As L o n g
Low As L o n g
End T y p e

Type MsdAddAttachmentFlags
C e n t e r As P o i n t 3 d
S t a r t As D o u b l e
Sweep As D o u b l e
V e c t o r 0 As P o i n t 3 d
V e c t o r 9 0 As P o i n t 3 d
End T y p e

Type MsdAngleAccuracy
Du As P o i n t 3 d
Dv As P o i n t 3 d
End T y p e
I The Microstation Object Model -Types I 281

Type MsdAngleAccuracy
RowX As P o i n t 3 d
RowY As P o i n t 3 d
RowZ As P o i n t 3 d
End T y p e

Type MsdAngleAccuracy
B a s e As M s d M e a s u r e m e n t B a s e
L a b e l As S t r i n g
S y s t e m As M s d M e a s u r e m e n t S y s t e m
U n i t s P e r B a s e D e n o m i n a t o r As D o u b l e
U n i t s P e r B a s e N u m e r a t o r As D o u b l e
End T y p e

T y p e MsdAngl e F o r m a t
D e t a i l s As S t r i n g
Msg As S t r i n g
P r i o r i t y As M s d M e s s a g e C e n t e r P r i o r i t y
End T y p e

T y p e MsdAngl eMode
N o r m a l As P o i n t 3 d
O r i g i n As P o i n t 3 d
End T y p e

Type MsdAttachMode
X As D o u b l e
Y As D o u b l e
End T y p e

Type MsdBsplineCurveOffsetCuspType
X As D o u b l e
Y As D o u b l e
Z As D o u b l e
End T y p e

Type MsdBsplineCurveOffsetCuspType
H i g h As P o i n t 3 d
Low As P o i n t 3 d
End T y p e
282 I Chapter 13: The Microstation Object Model - Types I

Type MsdBsplineCurveType
D i r e c t i on As P o i n t 3 d
O r i g i n As P o i n t 3 d
End T y p e

Type MsdBsplineCurveType
Duu A s P o i n t 3 d
Duv A s P o i n t 3 d
Dvu A s P o i n t 3 d
Dvv A s P o i n t 3 d
End T y p e

Type MsdBsplineCurveType
E n d p o i n t As P o i n t 3 d
S t a r t P o i n t As P o i n t 3 d
End T y p e

Type M s d B s p l i n e P a r a m e t r i z a t i o n T y p e
RowX A s P o i n t 3 d
RowY A s P o i n t 3 d
RowZ A s P o i n t 3 d
T r a n s l a t i o n X As D o u b l e
T r a n s l a t i onY As D o u b l e
T r a n s l a t i o n Z As D o u b l e
End T y p e

Type MsdBsplineSurfaceType
X As Double
Y As Double
Z As Double
End T y p e

Type MsdBsplineSurfaceType
T y p e A s MsdXDatumType
Value As V a r i a n t
End T y p e

Each of these types is available to us when we are using Microstation


VBA. The Type,End Trpe declaration as shown is a standard VBA
convention. As a matter of fact, we can create our own Types inside
VBA. Custom T p e s are declared in the General Declarations area of a
I Review I 283

Code Module. For example, if we want a new type named Point4d: we


would use the code:

Type P o i n t 4 d
X As D o u b l e
Y As D o u b l e
Z As D o u b l e
A As D o u b l e
End Type

If this declaration is made, we can declare variables as follows:

Dim MyPoint A s P o i n t 4 d

As with enumerations, types will be used extensively as we continue


working with the Microstation VBA.

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.
The Microstation Object
Model - Events

Objects, as we have discussed, have properties, methods, and events. We


introduced events when we discussed creating a Visual Interface. When
a user clicks on a CommandButton, the click event of the
CommandButton is triggered. Microstation events are triggered as the
user interacts with various aspects of Microstation.
When a company (such as Bentley) embeds VBA into their application
(in this case, Microstation), the question of how to deal with events is
raised. Here is how Microsoft Excel deals with events:

Each worksheet in an Excel workbook has events automatically exposed.


Two of them are the Change and the Selectionchange events. These

285
286 I Chapter 14: The Microstation Object Model - Events I
events are triggered as a worksheets cell value changes and when the
user moves from one cell to another.
There are two ways we can capture and make use of Microstation
events. One is to declare a variable in a class module or a form as an
application and using the WithEvents keyword. This exposes two
events: OnDesi gnFi 1 eOpened and OnDesi gnFi 1 eC1 osed. The majority of
Microstation events are accessed through the use of interfaces.
Microstation has exposed much more than simple events through the
use of interfaces, which are discussed in detail in Chapters 22
through 26.

0NDESIGN
FILEOPENED AND 0NDESIGNFILECLOSED
Here is a small example of how the OnDesignFileOpened and
OnDesignFi 1 eC1 osed events work.
We will use a UserForm that is shown modeless. This means the user
can still interact with Microstation even though the form is displayed.
When the form is initialized, we set the Microstation application object
to a variable that has been declared WithEvents in the General
Declarations area of the UserForm. When we declare a variable
WithEvents: the events belonging to the object we specify are available
to our code.
Heres the program as it is running after a couple of files have been
opened (the previous file closes when the new file is opened).

....C:\M/cr.ostation
..... VBAZ\filel .dgn
C:\Microstation VBAZ\Mathcad Model.dgn

C:\Docurnents and Settings\All Users\Application Data\Bentley\WorWpace\Projects\Exarnples\E


C:\Microstation VBAZ\filel .dgn
I OnDesignFileOpened and OnDesignFileClosed I 287

Each time a file is opened or closed, the associated event is triggered. We


will begin by looking at the code in the code area of the UserForm.

Dim WithEvents MyApp As MicroStationDGN.App1ication

Private Sub UserForm-Initialize0


Set MyApp = Application
End Sub

Private Sub MyApp-OnDesignFileOpened(ByVa1 -


DesignFileName As String)
1stOpened.AddItem DesignFileName
End Sub

Private Sub MyApp-OnDesignFileClosed(ByVa1 -


DesignFileName As String)
1stClosed.AddItem DesignFileName
End Sub
Each time the OnDesignFileOpened 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 form as modeless, so we will display it by
running the next macro:

Sub ShowEventsO
frmEvents.Show vbModeless
End Sub
The Procedure ShowEvents is placed inside a code module.
We can use the OnDesignFi 1 eOpened and OnDesignFi 1 eC1 osed events to
log which files have been opened. We are given the file name as a
parameter in the event. This basic functionality could be expanded to
include capturing the current Date/Time (with the Now Function) as well
as the current User (with the Appl ication .UserName property).
288 I Chapter 14: The Microstation Object Model - Events I

REVIEW
Events are triggered as users interact with software. Microstation events
are primarily exposed through the use of interfaces (covered later). The
OnDesignFileOpened and OnDesignFileClosed events can be exposed
by declaring the MicroStation.Application object WithEvents in a
Class Module or UserForm. More information on the use of
WithEvents can be found in the standard VBA help file.
15 Adding To Documents

We have created lines, circles, arcs, and text as we introduced


programming topics. Lets 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
Creating New Documents
Security Issues with Creating Data

GRAPHICAL
ELEMENTS
There are two steps to adding elements to our design files. First we
create the element in memory. Then we add the element to our design
file. As you will see, there is often more than one way to create the
element. We will demonstrate multiple examples of each creation
method.

Lines
The shortest distance between two points is a straight line. If this is
true, we should be able to create a line by providing two points, right?

289
290 I Chapter 15: Adding To Documents I
Well, that is one way to create a line. We can also provide an array of
vertices if we want to draw more than one line.
F u n c t i o n CreateLineElementl(Temp1ate As E l e m e n t ,
V e r t i c e s 0 A s P o i n t 3 d ) As L i n e E l e m e n t
F u n c t i o n CreateLineElement2(Template As E l e m e n t ,
S t a r t p o i n t As P o i n t 3 d , E n d p o i n t As P o i n t 3 d ) As
L i neEl ement

Sub T e s t C r e a t e L i n e A ( )
D i m S t P t As P o i n t 3 d
D i m EnPt As P o i n t 3 d
D i m m y L i n e As L i n e E l e m e n t
EnPt.X = 4 : EnPt.Y = 6 : EnPt.Z = 8
Set myLine = CreateLineElementZ(Nothing, S t P t , E n P t )
ActiveModel Reference.AddElement myLine
End Sub

T e s t C r e a t e L i n e A uses the C r e a t e L i n e E l e m e n t P method to create a new


line element. It does so using a start point and an end point.

Sub T e s t C r e a t e L i n e B ( )
D i m S t P t As P o i n t 3 d
D i m EnPt As P o i n t 3 d
D i m m y L i n e As L i n e E l e m e n t
'Line 1
StPt.X = 0: S t P t . Y = 0: S t P t . Z = 0
EnPt.X = 4 : EnPt.Y = 0 : EnPt.Z = 0
Set myLine = CreateLineElementZ(Nothing, S t P t , E n P t )
ActiveModel Reference.AddElement myLine
'Line 2
StPt.X = 4: S t P t . Y = 0: S t P t . Z = 0
EnPt.X = 4 : EnPt.Y = 4 : EnPt.Z = 0
Set myLine = CreateLineElementZ(Nothing, S t P t , E n P t )
ActiveModel Reference.AddElement myLine
'Line 3
StPt.X = 4: S t P t . Y = 4: S t P t . Z = 0
EnPt.X = 0 : EnPt.Y = 4 : EnPt.Z = 0
Set myLine = CreateLineElementZ(Nothing, S t P t , E n P t )
A c t i v e M o d e l R e f e r e n c e . A d d E l e m e n t myLi ne
'Line 4
StPt.X = 0: S t P t . Y = 4: S t P t . Z = 0
EnPt.X = 0 : EnPt.Y = 0 : EnPt.Z = 0
I Graphical Elements I 291

Set myLine = CreateLineElementZ(Nothing, S t P t , EnPt)


ActiveModel Reference.AddElement myLine
End Sub

TestCreatelineB creates and adds four lines by using the


Createli neEl emen t2 function. As we look at the coordinates used to
create the lines we will recognize that we are drawing a square. Let's
create the same square by using the Createli neEl ementl Method.

Sub TestCreateLineC( 1
D i m L i n e P o i n t s ( 0 To 4 ) As P o i n t 3 d
D i m m y L i n e As L i n e E l e m e n t
LinePoints(O).X = 0: LinePoints(O).Y = 0
LinePoints(l).X = 4: L i n e P o i n t s ( l ) . Y = 0
LinePoints(Z).X = 4: L i n e P o i n t s ( Z ) . Y = 4
LinePoints(3).X = 0: L i n e P o i n t s ( 3 ) . Y = 4
LinePoints(4).X = 0: L i n e P o i n t s ( 4 ) . Y = 0
S e t myLi ne = C r e a t e L i neEl e m e n t l ( N o t h i ng, L i nePoi n t s )
ActiveModel Reference.AddElement myLine
End Sub

As we can see in TestCreatelineC, we can supply an array of Point3d


types and use a single Createli neEl ementl Method to create four lines.
NOTE: W h e n we declare a numeric variable, a value of zero (0) is
automatically assigned to the variable. Knowing this, we can leave
the .Z element of each point alone and it will be assigned a value of
zero by default. W e could have left out the .Xa n d . Y elements that
were to be assigned values of zero as well, but keeping them in makes
the code much easier to read. Also, note that we are putting two lines
of code on the same line. W e can do this by using the colon (:) symbol.
This keeps our vertices on the same line of code and can make it easier
to read the code.
In our next example, we are going to create a procedure that allows us to
specify x, y, z elements for the creation of 3d Lines. We want to be able to
provide any number of x, y, z sets of elements so we will use the
ParamArray keyword in our parameter declaration.

Sub Create3dLines(ParamArray P o i n t E l e m s O As V a r i a n t )
I f (UBound(PointE1ems) + 1) Mod 3 <> 0 Then
MsgBox " I n v a l i d number o f p o i n t e l e m e n t s . " , vbcritical
E x i t Sub
I Chapter 15: Adding To Documents I
End I f
I f UBound(PointE1ems) + 1 < 5 Then
MsgBox A minimum o f 2 X , Y , Z p o i n t s m u s t b e p r o v i d e d . , v b c r i t i c a l
E x i t Sub
End I f
D i m L i n e P o i n t s O As P o i n t 3 d
ReDim L i n e P o i n t s ( 0 To ( U B o u n d ( P o i n t E 1 e m s ) + 1) \ 3 ) As P o i n t 3 d
D i m I As L o n g
D i m P o i n t c o u n t e r As L o n g
D i m m y L i n e As L i n e E l e m e n t
F o r I = L B o u n d ( P o i n t E 1 e m s ) To U B o u n d ( P o i n t E 1 e m s ) S t e p 3
LinePoints(PointCounter).X = PointElems(1)
LinePoints(PointCounter).Y = PointElems(1 + 1)
LinePoints(PointCounter).Z = PointElems(1 + 2)
Pointcounter = Pointcounter + 1
Next I
Set myLine = CreateLineElementl(Nothing, L i n e P o i n t s )
A c t i v e M o d e l Reference.AddE1 ement m y L i n e
End S u b

This procedure is straightforward but a little more complicated than


those we have worked with in the past. Lets start at the top of the
procedure and work our way down to the end.
The procedure is named Create3dLines and a single ParamArray
parameter is declared.
NOTE: Only one ParamArray parameter can be declared in a function
orprocedure and it must be the lastparameter.
3D Points are comprised of x,y, and z elements. Because of this, we
need to make sure that we have been given the PointElems array in
groups of 3. If the upper-bound value of the parameter is 4, this
means 5 elements have been provided. This is a problem because 5
elements do not produce two complete 3-D points.
If we pass the group of 3 elements test, we need to see if we have
been provided at least two points. After all, we cannot create a line
from one point. This can be done a number of different ways. One
way is to look at the upper-bound (UBound Function) of the
PointElems array. If it is less than 5, we know we dont have enough
elements in the array. If it is equal to 5 we know we have two
complete 3d Point elements.
I Graphical Elements I 293

4 Since the number of points may be different each time this


procedure is used, we need to create a dynamic array of points. We
then set the number of points in the array based on the number of
PointElems provided.
5 Now we need to populate the X, Y, and Z components of the points
based on the elements provided in the ParamArray.
6 Weuse CreateLineElement1,usingthepointscreatedfromthe
ParamArray.
7 We add the line to the ActiveModelReference.
Since this procedure utilizes parameters, it cannot be run by itself. Here
is a test procedure to run our Create3dLine.Sprocedure.

Sub TestCreate3dLines(1
C r e a t e 3 d L i n e s 0 , 0 , 0 , 4, 0, 0, 4, 4, 0, 0, 4, 0, 0 , 0 , 0
C r e a t e 3 d L i n e s 0, 0, 0, 4, 4, 0
C r e a t e 3 d L i n e s 0, 4, 0, 4, 0, 0
C r e a t e 3 d L i n e s 0, 4, 0, 4, 0
C r e a t e 3 d L i n e s 0, 4, 0
End S u b

Our test procedure, TestCreate3dLi nes, calls our newly created


procedure Create3dLines five times. In the first instance, a square is
created from (O,O,O) to (4,0,0) to (4,4,0) to (0,4,0) and back to (O,O,O).
The next one draws a line from (O,O,O) to (4,4,0). Next we draw a line
from (0,4,0) to (4,0,0). The next two lines are put in to test our
ParamArray validation code. We are unable to draw a line from (0,4,0)
to (4,O) because the second point is only given two elements (x and y)
and we are requiring three elements per point. The last one attempts to
draw a line from (0,4,0) to ... to nothing. We cannot draw a line with
only one point. Here are the two message boxes in the order in which
they appear.

Once a line is created, we can make changes to its properties such as its
color, level, or linestyle properties.
294 I Chapter 15: Adding To Documents I
In Microstations 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).

Lets draw a couple of lines and change their color to red (255,0,0).

Sub T e s t C r e a t e L i n e D ( )
Dim LinePoints(0 To 11 As Point3d
Dim myLine As LineElement
LinePoints(O1.X = 0: LinePoints(O1.Y = 0
LinePoints(l1.X = 4: LinePoints(l1.Y = 4
Set myLine = CreateLineElementl(Nothing, LinePoints)
myLine.Color = 3
ActiveModel Reference.AddElement myLine
LinePoints(O1.X = 0: LinePoints(O1.Y = 4
LinePoints(l1.X = 4: LinePoints(l1.Y = 0
Set myLine = CreateLineElementl(Nothing, LinePoints)
myLine.Color = 3
ActiveModel Reference.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 T e s t C r e a t e L i n e E ( )
Dim LinePoints(0 To 11 As Point3d
Dim myLine As LineElement
Dim myLine2 As LineElement
LinePoints(O1.X = 0: LinePoints(O1.Y = 0
LinePoints(l1.X = 4: LinePoints(l1.Y = 4
Set myLine = CreateLineElementl(Nothing, LinePoints)
I Graphical Elements I 295

myLine.Color = 3
ActiveModel Reference.AddElement myLine
LinePoints(O).X = 0: LinePoints(O).Y = 4
LinePoints(l).X = 4: LinePoints(l).Y = 0
Set myLine2 = CreateLineElementl(myLine, LinePoints)
ActiveModel Reference.AddElement myLine2
End S u b
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 myLi ne2 = CreateLi neEl ementl(myLi ne, Li nePoi nts)


In the previous work we did with CreateLineElementl, we supplied a
value of Nothing in the template parameter. In this example, we
provided the variable of the first line we created. This results in the
creation of a new line with the same non-geometric properties as the
Templateelement.

Creating Shapes
A shape is a series of lines that are joined together into one element.
Here is the declaration for CreateShapeElementl:
i
l Function CreateShapeElementl(Temp1ate As Element,
V e r t i c e s 0 As Point3d, CFillMode As MsdFillMode =
msdFillModeUseActive1) As ShapeElement
Here is a procedure that creates a triangle.

Sub TestCreateShapeA( )
Dim myshape As ShapeElement
Dim ShapePoints(0 T o 2) As Point3d
ShapePoints(O).X = 0: ShapePoints(O).Y = 0
ShapePoints(l).X = 2: ShapePoints(l).Y = 0
ShapePoints(Z).X = 1: ShapePoints(Z).Y = 1
Set myshape = CreateShapeElementl(Nothing, ShapePoints)
ActiveModel Reference.AddElement myshape
End S u b
When this code is run, a triangle is created and added to the
ActiveModelReference. Notice that we do not need to close the triangle
by providing a fourth point at (O,O, 0). Shapes are always closed.
296 I Chapter 15: Adding To Documents I
A comparison of the declaration and the use of C r e a t e S h a p e E l e r n e n t l
reveals that we did not use the optional FillMode parameter. By default,
the FillMode parameter uses the active setting in Microstation. Lets
copy and paste TestCreateShapeA, rename the new procedure to
T e s t C r e a t e S h a p e B and supply a FillMode parameter:

Sub T e s t C r e a t e S h a p e B O
D i m myshape As S h a p e E l e m e n t
D i m S h a p e P o i n t s ( 0 To 2) As P o i n t 3 d
ShapePoints(O1.X = 0: ShapePoints(O1.Y = 0
ShapePoints(l1.X = 2: S h a p e P o i n t s ( l 1 . Y = 0
ShapePoints(2l.X = 1: S h a p e P o i n t s ( 2 l . Y = 1
S e t myshape = CreateShapeElementl(Nothing, S h a p e P o i n t s , -
m s d F i 11 ModeFi 11 e d )
ActiveModelReference.AddElement myshape
End S u b

T e s t C r e a t e S h a p e B creates a filled triangle. If the resulting triangle does


not look like it is filled, the fill setting in view attributes may not be
selected (Settings > View Attributes).
Lets build on our knowledge of creating shapes. Now we are going to
create a function that creates a regular polygon based on a center point,
a number of sides, and a radius. The polygon we create will be inscribed
within the radius we provide.

F u n c t i o n C r e a t e P o l y g o n ( C e n t e r P o i n t As Poi n t 3 d . -
NumOfSides As L o n g , R a d i u s As D o u b l e ) As S h a p e E l e m e n t
D i m myshape As S h a p e E l e m e n t
D i m S h a p e P o i n t s O As P o i n t 3 d
ReDim S h a p e P o i n t s ( 0 To NumOfSides - 1) As P o i n t 3 d
D i m P o i n t I n d e x As L o n g
D i m I n c A n g l e As D o u b l e
IncAngle = 3 6 0 / NumOfSides
For P o i n t I n d e x = L B o u n d ( S h a p e P o i n t s ) To U B o u n d ( S h a p e P 0 i n t s )
ShapePoints(Point1ndex) = -
Point3dAddAngleDistance(CenterPoint, ~

R a d i a n s ( I n c A n g 1 e * P o i n t I n d e x ) , R a d i u s , 0)
Next
Set CreatePolygon = CreateShapeElementl(Nothing, S h a p e P o i n t s )
End F u n c t i o n

This is our function. It returns a ShapeElement. Since it utilizes


parameters, we need to create a test procedure to run it.
I Graphical Elements I 297

S u b TestCreatePolygon( 1
D i m C P o i n t As P o i n t 3 d
D i m m y s h a p e As S h a p e E l e m e n t
S e t myshape = C r e a t e P o l y g o n ( C P o i n t , 6 , 1)
A c t i v e M o d e l Reference.AddElement myshape
End S u b

Our TestC re ate Po 1 y g o n procedure declares a variable as a Point3d. No


modification is made to the X, Y,or Z elements of the point so the
polygon is created centered around (0, 0,O).

A circle is defined by a center point and a radius or diameter. We create


circles in Microstation VBA by using the CreateEll ipseEl ementl and
CreateEll ipseEl ement2 methods.
il F u n c t i o n CreateEllipseElementl(Temp1ate As E l e m e n t ,
P e r i m e t e r P o i n t l As P o i n t 3 d , P e r i m e t e r P o i n t 2 As
P o i n t 3 d , P e r i m e t e r P o i n t 3 As P o i n t 3 d , C F i l l M o d e As
MsdFi 1 1 Mode = msdFi 11 ModeUseActi v e l ) As
E l 1 ipseEl ement
il F u n c t i o n CreateEllipseElementZ(Temp1ate As E l e m e n t ,
O r i g i n As Poi n t 3 d , P r i m a r y R a d i us As Doubl e ,
SecondaryRadius As D o u b l e , R o t a t i o n As M a t r i x 3 d ,
[ F i 11 Mode As MsdFi 11 Mode = msdFi 11 ModeUseActi v e l ) As
E l 1 ipseEl ement
I Chapter 15: Adding To Documents I
We will begin with C r e a t e E l l i p s e E l ernent2.

Sub T e s t C r e a t e C i r c l eA( )
D i m C P o i n t As P o i n t 3 d
D i m m y E l l i p s e As E l l i p s e E l e m e n t
D i m r o t M a t r i x As M a t r i x 3 d
CP0int.X = 2.5: C P 0 i n t . Y = 2.5
S e t myEllipse = CreateEllipseElementZ(Nothing, CPoint, 0 . 5 , 0 . 5 ,
rotMatrix)
A c t i v e M o d e l R e f e r e n c e . A d d E l e m e n t myEl1 i p s e
End Sub

The center point is set at (2.5,2.5,0) and we are using a radius of 0.5. We
supply the same value for the PrimaryRadius parameter as we do for the
SecondaryRadius parameter. This results in a circle. If the primary and
secondary radii values are different, an ellipse is created.

Sub T e s t C r e a t e C i r c l eB( )
D i m C P o i n t As P o i n t 3 d
D i m m y E l l i p s e As E l l i p s e E l e m e n t
D i m r o t M a t r i x As M a t r i x 3 d
D i m C i r R a d As D o u b l e
CP0int.X =2.5: C P 0 i n t . Y = 2.5
F o r CirRad = 0.5 To 2 S t e p 0.125
S e t m y E l l i p s e = CreateEllipseElementZ(Nothing, C P o i n t , -
CirRad, CirRad, r o t l v l a t r i x )
A c t i v e M o d e l R e f e r e n c e . A d d E l e m e n t myEl1 i p s e
N e x t C i rRad
End Sub

T e s t C r e a t e C ir c 1 e B creates 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 T e s t C r e a t e C i r c l eC( )
D i m C P o i n t As P o i n t 3 d
D i m m y E l l i p s e As E l l i p s e E l e m e n t
D i m r o t M a t r i x As M a t r i x 3 d
D i m i n p u t Q u e u e As CadInputQueue
D i m i n p u t M e s s a g e As CadInputMessage
Set inputQueue = CadInputQueue
I Graphical Elements I 299

Set inputMessage = -
inputQueue.GetInput(msdCadInputTypeDataPoint, ~

msdCadInputTypeAny)
Do
S e l e c t Case i n p u t M e s s a g e . I n p u t T y p e
Case m s d C a d I n p u t T y p e D a t a P o i n t
CPoint = inputMessage.point
S e t m y E l l i p s e = CreateEllipseElement2(Nothing, -
CPoint, 0.5, 0.5, r o t M a t r i x )
ActiveModelReference.AddElement m y E l l i p s e
E x i t Do
Case m s d C a d I n p u t T y p e R e s e t
E x i t Do
End S e l e c t
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 T e s t C r e a t e C i rcl eD( 1


D i m C P o i n t As P o i n t 3 d
D i m S t P o i n t As P o i n t 3 d
D i m E n P o i n t As P o i n t 3 d
D i m m y E l l i p s e As E l l i p s e E l e m e n t
D i m r o t M a t r i x As M a t r i x 3 d
D i m i n p u t Q u e u e As C a d I n p u t Q u e u e
D i m i n p u t M e s s a g e As C a d I n p u t M e s s a g e
D i m C i r R a d As D o u b l e
Set inputQueue = CadInputQueue
Set inputMessage = ~

inputQueue.GetInput(msdCad1nputTypeDataPoint. -
msdCadInputTypeAny)
Do
S e l e c t Case i n p u t M e s s a g e . 1 n p u t T y p e
Case m s d C a d I n p u t T y p e D a t a P o i n t
StPoint = inputMessage.point
E x i t Do
Case m s d C a d I n p u t T y p e R e s e t
E x i t Sub
End S e l e c t
Loop
I Chapter 15: Adding To Documents I
Set inputMessage = inputQueue.GetInput(rnsdCadInputTypeDataPoint, ~

msdCadInputTypeAny)
Do
S e l e c t Case i n p u t M e s s a g e . I n p u t T y p e
Case msdCadInputTypeDataPoint
EnPoint = inputMessage.point
E x i t Do
Case m s d C a d I n p u t T y p e R e s e t
E x i t Sub
End S e l e c t
Loop
CP0int.X = StP0int.X + (EnP0int.X - StP0int.X) / 2
CP0int.Y = StP0int.Y + (EnP0int.Y - StP0int.Y) / 2
CP0int.Z = StP0int.Z + (EnP0int.Z - StP0int.Z) / 2
C i r R a d = Point3dDistance(StPoint, E n P o i n t ) / 2
S e t m y E l l i p s e = CreateEllipseElementZ(Nothing, CPoint, -
CirRad, CirRad, r o t M a t r i x )
A c t i v e M o d e l Reference.AddElement myEl1i p s e
End Sub

We calculate the center point of the circle by using the selected points.
We also use the Microstation VBA P o i n t 3 d D i s t a n c e 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. Lets
look at three examples of creating ellipses.

Sub TestCreateEll ipseA( 1


D i m C P o i n t As P o i n t 3 d
D i m m y E l l i p s e As E l l i p s e E l e m e n t
D i m r o t M a t r i x As M a t r i x 3 d
CP0int.X = 2.5: CP0int.Y = 2.5
S e t m y E l l i p s e = CreateEllipseElementZ(Nothing, C P o i n t , 1, 0 . 5 ,
rotMatrix)
ActiveModelReference.AddElement m y E l l i p s e
End Sub

Sub TestCreateEll ipseB( 1


D i m M a j o r A l As P o i n t 3 d
D i m M a j o r A 2 As P o i n t 3 d
I Graphical Elements I 301

D i m M i n o r A l As P o i n t 3 d
D i m m y E l l i p s e As E l l i p s e E l e m e n t
MajorA1.X = 1: M a j o r A 1 . Y = 1
MajorA2.X = 5: MajorA2.Y = 5
MinorA1.X = 3: MinorA1.Y = 2
Set myEllipse = CreateEllipseElementl(Nothing, M a j o r A l , MajorAP, -
M inorAl)
ActiveModel Reference.AddElement myEl1 i p s e
End S u b

S u b TestCreateEl 1 ipseC()
D i m C P o i n t As P o i n t 3 d
D i m m y E l l i p s e As E l l i p s e E l e m e n t
D i m r o t M a t r i x As M a t r i x 3 d
CP0int.X = 2.5: CP0int.Y = 2.5
rotMatrix.RowX.X = 2
rotMatrix.RowY.X = 4: r0tMatrix.RowY.Y = 5
S e t m y E l l i p s e = CreateEllipseElementZ(Nothing, C P o i n t , 1, 0 . 5 ,
rotMatrix)
A c t i v e M o d e l Reference.AddElement myEl1 i p s e
End S u b

After running the above procedures, what do we find? Two of the three
procedures shown above create ellipses. However, the procedure
TestCreateEllipseB createdacircle. Themethod CreateEllipseElementl
always creates a circle through the three points provided.

Creating Arcs
We have five different ways we can create arcs in Microstation VBA.
Function CreateArcElement 1(Template As Element, StartPoint As
Point3d, Centerpoint As Point3d, Endpoint As Point3d) As
ArcElement
Function CreateArcElement2(TemplateAs Element, Centerpoint As
Point3d, PrimaryRadius As Double, SecondaryRadius As Double,
Rotation As Matrix3d, StartAngle As Double, SweepAngle As
Double) As ArcElement
Function CreateArcElement3(Template As Element, StartPoint As
Point3d, PointOnCurve As Point3d, Endpoint As Point3d) As
ArcElement
I Chapter 15: Adding To Documents I
4 Function CreateArcElement4(TemplateAs Element, StartTangent
As Ray3d, Endpoint As Point3d) As ArcElement
5 Function CreateArcElement5(TemplateAs Element, Chord As
Segment3d, ArcLength As Double, PlanePoint As Point3d) As
ArcElement
Lets look at a few ways to use these methods.

Sub T e s t C r e a t e A r c A (
D i m C P o i n t As P o i n t 3 d
D i m S t P o i n t As P o i n t 3 d
D i m E n P o i n t As P o i n t 3 d
D i m m y A r c As A r c E l e m e n t
CP0int.X = 1: C P 0 i n t . Y = 1
StP0int.X = 4: S t P 0 i n t . Y = 1
EnP0int.X = 1: E n P 0 i n t . Y = 4
S e t myArc = CreateArcElementl(Nothing, S t P o i n t , C P o i n t , E n P o i n t )
ActiveModelReference.AddElement m y A r c
End Sub

Sub T e s t C r e a t e A r c B (
D i m C P o i n t As P o i n t 3 d
D i m r o t M a t r i x As M a t r i x 3 d
D i m m y A r c As A r c E l e m e n t
CP0int.X = 1: C P 0 i n t . Y = 1
S e t m y A r c = CreateArcElementZ(Nothing, CPoint, 0.5, 0.5, -
r o t M a t r i x , 0, P i )
ActiveModelReference.AddElement m y A r c
End Sub

Sub T e s t C r e a t e A r c C o
D i m P o i n t A As P o i n t 3 d
D i m P o i n t B As P o i n t 3 d
D i m P o i n t C As P o i n t 3 d
D i m m y A r c As A r c E l e m e n t
P0intA.X = 1: P 0 i n t A . Y = 1
P0intB.X = 2: P 0 i n t B . Y = 2
P0intC.X = 1: P 0 i n t C . Y = 3
= CreateArcElement3(Nothing,
S e t myArc PointA, PointB, PointC)
ActiveModelReference.AddElement m y A r c
End Sub
I Graphical Elements I 303

Sub T e s t C r e a t e A r c D ( )
D i m m y A r c As A r c E l e m e n t
D i m myRay As Ray3d
D i m E n d p o i n t As P o i n t 3 d
myRay.0rigin.X = 1
myRay.0rigin.Y = 1
myRay.Directi0n.X = 1
myRay. D i r e c t i o n . Y = 4
EndP0int.X = 0: EndP0int.Y = 2
S e t myArc = C r e a t e A r c E l e m e n t 4 ( N o t h i n g , myRay, E n d p o i n t )
A c t i v e M o d e l Reference.AddElement myArc
End Sub

Sub T e s t C r e a t e A r c E ( )
D i m m y A r c As A r c E l e m e n t
D i m mySeg As Segment3d
D i m m y p o i n t As P o i n t 3 d
mySeg.startP0int.X = 1: m y S e g . s t a r t P 0 i n t . Y = 1
mySeg.EndP0int.X = 4: m y S e g . E n d P 0 i n t . Y = 4
myP0int.X = 3.5: myP0int.Y = 3: myP0int.Z = 0
S e t myArc = CreateArcElement5(Nothing, mySeg, 8 . 5 , myPoint)
A c t i v e M o d e l Reference.AddElement myArc
End Sub

Creating Text
Text is easy to create by using the CreateTextElementl method.
I4 F u n c t i o n CreateTextElementl(Temp1ate As E l e m e n t ,
T e x t As S t r i n g , O r i g i n A s P o i n t 3 d , R o t a t i o n A s
M a t r i x 3 d ) As TextElement
Here is an example of creating nine text elements spaced 0.5 units away
from each other.

Sub T e s t C r e a t e T e x t A ( 1
D i m m y T e x t As T e x t E l e m e n t
D i m T e x t P t As P o i n t 3 d
D i m r o t M a t r i x As M a t r i x 3 d
D i m I As D o u b l e
For I = 1 To 9
TextPt.Y = TextPt.Y - 0.5
304 I Chapter 15: Adding To Documents I
S e t myText = CreateTextElementl(Nothing, " N o t e " & I & -
":", TextPt, rotMatrix)
ActiveModelReference.AddElement m y T e x t
Next I
End S u b

I
j

.+. _.

j . .
I
I !

INote 5:
I
i .
I
.
. . . . . . . . .

Creating Cells
Thus far, all elements we have created have been added to the design file
as individual elements. When we begin working with cells, we work with
multiple elements as a single cell. We create the elements in the same
manner as when we are adding them to our model but instead of adding
I Graphical Elements I 305

the created element to the model we add it to the cell. We have three
options for creating cells.
1 Function CreateCellElement1(Name As String, Elements() As
-Element, Origin As Point3d, [IsPointCellAs Boolean]) As
CellElement
2 Function CreateCellElement2(CellName As String, Origin As
Point3d, Scale As Point3d, Truescale As Boolean, Rotation As
Matrix3d) As CellElement
3 Function CreateCellElement3(CellName As String, Origin As
Point3d, Truescale As Boolean) As CellElement
Our first example creates a cell named "Box". Four lines are added to an
array of elements. This array is used when we create the cell.

S u b TeStCreateCell A ( )
D i m m y C e l l As C e l l E l e m e n t
D i m BoxLines(0 To 3 ) As E l e m e n t
D i m O r i g i n p o i n t As P o i n t 3 d
Set BoxLines(0) = CreateLineElementZ(Nothing, ~

Point3dFromXYZ(O, 0 , O ) , Point3dFromXYZ(4, 0 , 0))


Set BoxLines(1) = CreateLineElementZ(Nothing, ~

Point3dFromXYZ(4, 0, O), Point3dFromXYZ(4, 4 , 0))


Set BoxLines(2) = CreateLineElementZ(Nothing, -

Point3dFromXYZ(4, 4, O), P o i n t 3 d F r o m X Y Z ( O , 4 , 0))


Set BoxLines(3) = CreateLineElementZ(Nothing, ~

P o i n t 3 d F r o m X Y Z ( O , 4 , O ) , P o i n t 3 d F r o m X Y Z ( O , 0 , 0))
0riginPoint.X = 2: 0 r i g i n P o i n t . Y = 2
Set myCell = CreateCellElementl("Box", B o x L i n e s , O r i g i n p o i n t )
A c t i v e M o d e l Reference.AddElement myCel1
m y c e l l . Redraw
End S u b

TestCreateCellA creates A 4-unit square with an origin of (2,2,0).

S u b TestCreateCell B ( 1
D i m m y C e l l As C e l l E l e m e n t
D i m CellElements(0 To 6) As E l e m e n t
D i m O r i g i n p o i n t As P o i n t 3 d
D i m r o t M a t r i x As M a t r i x 3 d
Set CellElements(0) = CreateLineElementZ(Nothing, -
I Chapter 15: Adding To Documents I
Point3dFromXYZ(O, 0, 0). Point3dFromXYZ(4, 0, 0))
Set CellElements(1) = C r e a t e L i n e E l e m e n t Z ( N o t h i n g , -
Point3dFromXYZ(4, 0, 01, Point3dFromXYZ(4, 4, 0))
Set CellElements(2) = C r e a t e L i n e E l e m e n t Z ( N o t h i n g ,
~

Point3dFromXYZ(4, 4, 01, Point3dFromXYZ(O, 4, 0))


Set CellElements(3) = C r e a t e L i n e E l e m e n t Z ( N o t h i n g , -
Point3dFromXYZ(O, 4, 0). Point3dFromXYZ(O, 0, 0))
Set CellElements(4) = C r e a t e L i n e E l e m e n t Z ( N o t h i n g , -
Point3dFromXYZ(O, 0, 01, Point3dFromXYZ(4, 4, 0))
Set CellElements(5) = C r e a t e L i n e E l e m e n t Z ( N o t h i n g ,
~

Point3dFromXYZ(4, 0, 01, Point3dFromXYZ(O, 4, 0))


0riginPoint.X = 2: 0riginPoint.Y = 2
Set CellElements(6) = CreateEllipseElementZ(Nothing, -
Originpoint, 1.25, 1.25, rotMatrix)
Set myCell = CreateCellElementl("Box2", CellElements, -
Ori gi nPoi nt)
ActiveModelReference.AddElement myCell
myCel1 .Redraw
End Sub
As the number of elements we want in a cell increases, the upper-bound
array number increases. Six lines and a circle are used in
TestCreateCell B to create a cell named "Box2".
Creating cells is easy to do as we have already seen. Adding the cell to a
cell library makes the creation of the cell useful in other files.

Sub TestCreateCell C( )
Dim myCell As CellElement
Dim CellElements(0 To 6 ) As Element
Dim Originpoint As Point3d
Dim rotMatrix As Matrix3d
Set CellElements(0) = C r e a t e L i n e E l e m e n t Z ( N o t h i n g ,~

Point3dFromXYZ(O, 0, 01, Point3dFromXYZ(4, 0, 0))


Set CellElements(1) = C r e a t e L i n e E l e m e n t Z ( N o t h i n g ,~

Point3dFromXYZ(4, 0, 0). Point3dFromXYZ(4, 4, 0))


Set CellElements(2) = C r e a t e L i n e E l e m e n t Z ( N o t h i n g , -
Point3dFromXYZ(4, 4, 01, Point3dFromXYZ(O, 4, 0))
Set CellElements(3) = C r e a t e L i n e E l e m e n t Z ( N o t h i n g ,~

Point3dFromXYZ(O, 4, 01, Point3dFromXYZ(O, 0, 0))


Set CellElements(4) = C r e a t e L i n e E l e m e n t Z ( N o t h i n g , -
Point3dFromXYZ(O, 0, 0). Point3dFromXYZ(4, 4, 0))
Set CellElements(5) = C r e a t e L i n e E l e m e n t Z ( N o t h i n g , -
I Creating New Documents I 307

Point3dFromXYZ(4, 0, O), Point3dFromXYZ(O, 4, 0))


0riginPoint.X = 2: 0riginPoint.Y = 2
Set CellElements(6) = CreateEllipseElement2(Nothing, ~

Originpoint, 1.25, 1.25, rotMatrix)


Set myCell = CreateCellElementl("Box3", CellElements, -
Ori gi nPoi nt)
ActiveModel Reference.AddElement myCel1
mycell. Redraw
Application.AttachCel1 Library "MicroStation VBA.ce1"
Application.AttachedCellLibrary.AddCel1 mycell, ~

M BOX^", M BOX^", 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.

CREATINGNEWDOCUMENTS
We have drawn lines, circles, ellipses, arcs, text, and cells to the current
design file. This assumes we have a file to work with. How do we create
new design files?
1 Function CreateDesignFile(SeedFileName As String,
NewDesignFileName As String, Open As Boolean) As DesignFile
2 Sub CopyDesignFile(ExistingDesignFileNameAs String,
NewDesignFileName As String, [Overwrite As Boolean])
308 I Chapter 15: Adding To Documents I
Here are two methods that create new design files. CreateDesignFile
allows us to specify whether the new file is to be a 2D or 3D file by
specifying the seed document. Let's look at a couple of examples.

Sub T e s t C r e a t e D e s i g n F i l e A ( )
D i m m y F i l e As D e s i g n F i l e
A p p l i c a t i o n . A c t i v e D e s i g n F i 1 e.C1 o s e
S e t m y F i l e = CreateDesignFile("seedZd", ~

" C : \ M i c r o S t a t i o n V B A \ f i 1e a . d g n " , T r u e )
End Sub

TestCreateDesignFileA creates a new 2D design file. The file path and


name are specified. After the CreateDesi gnFi 1 e 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 T e s t C r e a t e D e s i g n F i l e B O
D i m m y F i l e As D e s i g n F i l e
D i m m y F i l e N a m e As S t r i n g
myFileName = "C:\MicroStation VBA\filea.dgn"
I f Dir(myFileName1 = " " Then
Set myFile = CreateDesignFile("seed3d", m y F i l e N a m e , T r u e )
Else
MsgBox " T h e f i l e " & myFileName & " already exists.", ~

vbCri tical
End I f
End S u b

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 T e s t C r e a t e D e s i g n F i l e C O
D i m m y F i l e As D e s i g n F i l e
D i m I As Long
F o r I = 1 To 1 0
Set myFile = CreateDesignFile("seed2d","C:\MicroStation
VBA\file" & I & ".dgn", False)
Next I
End Sub
I Security Issues with Creating Data I 309

How many files does TestCre-


ateDesignFileC Create? It Cre- file1 dgn 34 KB Bentley Microstation Design File
file2 dgn 34 KB Bentley Microstation Design File
ten (''1 Each is a file3 dgn 34 KB Bentley Microstation Design File
new 2D fie and the files are file4 dgn 34 KB Bentley Microstation Design File
file5 dgn 34 KB Bentley Microstation Design File
not opened in Microstation file6 dgn 34 KB Bentley Microstation Design File
file7 dgn 34 KB Bentley Microstation Design File
(the False Parameter). file8 dgn 34 KB Bentley Microstation Design File
file9 dgn 34 KB Bentley Microstation Design File
file10 dgn 34 KB Bentley Microstation Design File

SECURITY ISSUES WITH CREATING DATA


Our ability to create data in Microstation using VBA is dependent on
our security settings. VBA is not intended to bypass these security
settings. Writing and attempting to run the procedures in this chapter
on one machine may result in the intended creation of data. Other
machines with different security permissions may cause the code to fail.
CAD administrators should be able to provide the appropriate
permissions if this becomes a problem.

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.
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:
The Basics of Searching Files
Using Scancriteria
Multiple Combinations of Criteria
Reviewing Three Collection Methods
Scan Criteria Methods

THEBASICSOF SEARCHING FILES


Lets begin by examining each element found in a file.

S u b TestScanAl 1A ( )
Dim myElement A s Element
Dim myEnum A s ElementEnumerator

311
312 I Chapter 16: Searching In Files I
S e t myEnum = ActiveModelReference.Scan0
W h i l e myEnum.MoveNext
S e t myElement = myEnum.Current
D e b u g . P r i n t myElement.Type
Wend
End Sub

This procedure prints the type


9
property value of each element in the
96 active model to the Immediate
96
97
Window.
66
96 Running the procedure T e s t S c a n A l 1 A
96 results in a list of numbers telling us
96
96 the type of element found. This
66
66
number references the
6 msdElementType enumeration.
4

Here is a listing of the msdElementType enumerationsmembers:

msdXDatumTypeWorldSpacePosition
msdEl ementType44 = 44
msdEl ementTypeArc = 16
msdElementTypeBsplineBoundary = 25
msdElementTypeBsplineCurve = 27
msdEl ementTypeBsp1 ineKnot = 26
msdEl ementTypeBsp1 inePol e = 21
msdElementTypeBsplineSurface = 2 4
msdElementTypeBsplineWeight = 28
msdEl ementTypeCel1 Header = 2
msdEl ementTypeCel1 Li braryHeader = 1
msdEl ementTypeComp1 exshape = 1 4
msdEl ementTypeComp1 exstring = 1 2
msdEl ementTypeCone = 23
msdElementTypeConic = 13
msdElementTypeCurve = 11
msdElementTypeDesignFileHeader = 9
msdElementTypeDgnStoreComponent = 38
msdElementTypeDgnStoreHeader = 39
msdElementTypeDigSetData = 8
I The Basics of Searching Files I 313

msdElementTypeDimension = 33
msdEl ementTypeEl1 ipse = 15
msdElementTypeGroupData = 5
msdEl ementTypeLeve1 Mas k = 99
msdEl ementTypeLeve1 Symbol ogy = 10
msdEl ementTypeLine = 3
msdElementTypeLineString = 4
msdEl ementTypeMatrixDoub1 eData = 103
msdElementTypeMatrixHeader = 101
msd El emen tTypeMa t r i x I n teger Da ta = 102
m s d E l e m e n t T y p e M e s h H e a d e r = 105
msdElementTypeMicroStation = 66
msdEl ementTypeMu1 ti Line = 36
msdElementTypeNamedGroupComponent = 111
msdElementTypeNamedGroupHeader = 110
msdEl ementTypePointString = 22
msdElementTypeRasterComponent = 88
msdElementTypeRasterFrame = 94
msdElementTypeRasterHeader = 87
m s d E l e m e n t T y p e R a s t e r R e f e r e n c e = 90
msdElementTypeRasterReferenceComponent = 91
m s d E l e m e n t T y p e R e f e r e n c e A t t a c h m e n t = 100
msdElementTypeReferenceOverride = 108
msdElementTypeShape = 6
msdEl ementTypeSharedCel1 = 35
msdElementTypeSharedCel1 Definition = 34
msdEl ementTypeSo1 id = 19
msdEl ementTypeSurface = 18
msdEl ementTypeTab1 e = 96
msdEl ementTypeTab1 eEntry = 95
msdElementTypeTag = 37
msdElementTypeText = 17
msdElementTypeTextNode = 7
msdEl ementTypeView = 98
msdEl ementTypeViewGroup = 97
A review of the Immediate window, shown previously, shows the first
three unique element types are 9, 96, and 97. Referring to the list above
tells us the first three element types found were:
314 I Chapter 16: Searching In Files I
msdElementTypeDesignFileHeader = 9
msdEl ementTypeTab1 e = 96
msdEl ementTypeViewGroup = 97
Not exactly lines, circles, or arcs, right? Microstation design files are
composed of far more than what we see on the screen as we are working
with Microstation. What are the next three element types? 6 6 , 6 , and 4.

msdEl ementTypeMi croStati on = 66


msdElementTypeShape = 6
msdEl ementTypeLineString = 4
Now were getting somewhere. We can see shapes and linestrings.
We are going to do a lot of copy and paste operations in this chapter.
Lets begin by copying and pasting TestScanAll A as TestScannAll B.

Sub TestScanAll B ( 1
D i m m y E l e m e n t As E l e m e n t
D i m myEnum As E l e m e n t E n u m e r a t o r
S e t myEnum = ActiveModelReference.Scan0
W h i l e myEnum.MoveNext
S e t myElement = myEnum.Current
S e l e c t Case m y E l e m e n t . T y p e
Case m s d E l e m e n t T y p e A r c
D i m m y A r c As A r c E l e m e n t
S e t myArc = myElement
Case m s d E l e m e n t T y p e C u r v e
D i m m y c u r v e As C u r v e E l e m e n t
S e t mycurve = myEl e m e n t
Case msdEl e m e n t T y p e L i n e
D i m m y L i n e As L i n e E l e m e n t
Set myLine = myElement
Case m s d E l e m e n t T y p e T e x t
D i m m y T e x t As T e x t E l e m e n t
S e t myText = myEl e m e n t
Case E l s e
D e b u g . P r i n t myElement.Type
End S e l e c t
Wend
End Sub

We can make the use of a Sel ect ... Case statement to allow us to
perform actions based on the Element.Type property. As we cycle
I The Basics of Searching Files I 315

through each element in our ElementEnumerator we set each element to


a generic element object. If we want to work with a LineElement we
could do so through the generic element object but declaring a variable
as a LineElement makes our programming tasks much easier. Lets see
why this is true.

Subiype SetXData
Transform Subiype
Type Transform
URL Type
URLTitie URL
Vertex URLTitie

As we are programming, which list would help us most if we are


working with a line element? The list on the left gives us a Startpoint
property. Lines have start points. The list on the right does not have a
Startpoint in the list. If we declare a variable as a LineElement we will
see line-specific properties in addition to the standard element
properties.
Lets do a little more with the above procedure. Copy and paste it as
Tes t S c a n A l 1 C. After doing so, we are going to remove everything inside
the Se 1 e c t ... Case statement except for the Case msdElementTpeText
area.

S u b TestScanAl 1 C ( )
D i m myElement As Element
D i m myEnum A s E l e m e n t E n u m e r a t o r
S e t myEnum = ActiveModelReference.Scan0
W h i l e myEnum.MoveNext
S e t myElement = myEnum.Current
S e l e c t Case m y E l e m e n t . T y p e
Case m s d E l e m e n t T y p e T e x t
D i m myText As T e x t E l e m e n t
S e t myText = myElement
myText.Text = UCase(myText.Text)
End S e l e c t
Wend
End S u b

Now, our procedure is only going to react to text elements. And what are
we doing to the text element? U C a s e capitalizes everything. The result of
this procedure should be the capitalization of all text elements, right?
316 I Chapter 16: Searching In Files I
After this code is executed we should find that nothing has changed.
How is this possible? The code is capitalizing the text. Lets take a look at
the next procedure and see if we can find what is missing.

Sub T e s t S c a n A l l D ( 1
D i m m y E l e m e n t As E l e m e n t
D i m myEnum As E l e m e n t E n u m e r a t o r
S e t myEnum = ActiveModelReference.Scan0
W h i l e myEnum.MoveNext
S e t myElement = myEnum.Current
S e l e c t Case m y E l e m e n t . T y p e
Case m s d E l e m e n t T y p e T e x t
D i m m y T e x t As T e x t E l e m e n t
S e t myText = myEl e m e n t
myText.Text = UCase(myText.Text)
myText. R e w r i t e
End S e l e c t
Wend
End Sub

If we dont 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.

USINGSCANCRITERIA
Now, lets 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. Lets make our code more efficient by working
only with text elements. We accomplish this through the use of an
Elementscancriteria object.

Sub T e s t S c a n F i 1 t e r A ( )
D i m myEnum As E l e m e n t E n u m e r a t o r
D i m myFi 1 t e r As New E l e m e n t S c a n C r i t e r i a
D i m E l e m e n t c o u n t e r As L o n g
myFi 1 t e r . I n c l u d e T y p e msdEl e m e n t T y p e T e x t
myFi 1 t e r . I n c l u d e T y p e msdEl e m e n t T y p e T e x t N o d e
I Using Scancriteria I 317

Set myEnum = A c t i v e M o d e l R e f e r e n c e . S c a n ( m y F i 1 t e r )
While myEnum.MoveNext
Elementcounter = Elementcounter + 1
Wend
MsgBox Elementcounter & elements found."
"

End Sub
When we include Text and TextNode elements, we should only be
counting the number of Text and TextNode elements. After running this
code, however, we find that something is not working as expected.
On careful examination we find that, by default, Scancriteria includes
everything. Before specifying which elements we want to look at, we
need to exclude everything and then include those elements with which
we want to work.

Sub TestScanFi 1 t e r B ( 1
Dim myEnum As ElementEnumerator
Dim myFilter As New Elementscancriteria
Dim Elementcounter A s Long
myFilter.ExcludeA11Types
myFil ter.IncludeType msdElementTypeText
myFilter.IncludeType msdElementTypeTextNode
Set myEnum = A c t i v e M o d e l R e f e r e n c e . S c a n ( m y F i 1 t e r )
While myEnum.MoveNext
Elementcounter = Elementcounter + 1
Wend
MsgBox Elementcounter & elements found."
"

End Sub
Now, myEnum only contains Text and TextNode elements.
Let's build on T e s t S c a n F i 1 terB by adding a filter for a specific level.
Before we look for a specific Level, we must first exclude all levels. If we
miss this critical step, we will be retrieving all levels.

Sub TestScanFi 1 t e r C ( 1
Dim myEnum A s ElementEnumerator
Dim myFilter A s New ElementScanCriteria
Dim Elementcounter As Long
myFilter.ExcludeA11Types
myFi 1 ter. Excl udeAl1 Levels
myFil ter.IncludeType msdElementTypeText
myFilter.IncludeType msdElementTypeTextNode
I Chapter 16: Searching In Files I
myFilter.IncludeLeve1 ActiveDesignFile.Levels("SIDEWALK")
Set myEnum = ActiveModelReference.Scan(myFi1ter)
While myEnum.MoveNext
Elementcounter = Elementcounter + 1
Wend
MsgBox Elementcounter & elements found."
"

End Sub
Let's look over the macro "ScanFilterc': What is being counted here?
Text elements and TextNode elements on Level "SIDEWALK':

Sub T e s t S c a n F i 1 t e r D ( )
Dim myEnum As ElementEnumerator
Dim myFi 1 ter As New El ementScanCri teria
Dim Elementcounter As Long
myFi 1 ter . Excl udeAl1 Types
myFi 1 ter. Excl udeAl1 Levels
myFi 1 ter. Excl udeAl1 Colors
myFi 1 ter. Incl udeType msdEl ementTypeText
myFi 1 ter. Incl udeType msdEl ementTypeTextNode
myFi 1 ter. Incl udeLevel ActiveDesignFi le. Level s("S1DEWALK")
myFi 1 ter. Incl udeCol or 4
Set myEnum = ActiveModelReference.Scan(myFi1ter)
While myEnum.MoveNext
Elementcounter = Elementcounter + 1
Wend
MsgBox Elementcounter & " elements found."
End Sub
We have added one more scan criteria. In addition to looking at the
element type and level, we are now looking at the color.
If we know a color's index in the document's color table, we can specify
it as shown above. Let's look at the next example where we specify an
RGB color value to filter for a specific color. We will also add one more
item in our scan criteria. Let's add a Linestyle criteria.

Sub T e s t S c a n F i 1 t e r F ( )
Dim myEnum As ElementEnumerator
Dim myFi 1 ter As New El ementScanCri teria
Dim Elementcounter As Long
Dim myCol orTabl e As Col orTabl e
Dim mycolor As Long
Set myColorTable = ActiveDesignFile.ExtractColorTable
I Using Scancriteria I 319

mycolor = myColorTable.FindClosestColor(RGB(l92, 192, 192))


myFilter.ExcludeA11Types
myFi 1t e r . E x c l u d e A l 1 L e v e l s
myFilter.ExcludeA11Colors
myFi 1t e r . E x c l u d e A l 1 L i n e S t y l e s
myFilter.IncludeType msdElementTypeLineString
m y F i l t e r . I n c l udeLi n e S t y l e A c t i v e D e s i g n F i 1 e . L i n e S t y l e s ( " ( Hidden 1 " )
m y F i 1 t e r . I n c l u d e L e v e l A c t i v e D e s i g n F i l e . L e v e l s ( "SIDEWALK")
m y F i 1 t e r . I n c l u d e C o l o r myCol o r - 1
S e t myEnum = ActiveModelReference.Scan(myFi1ter)
W h i l e myEnum.MoveNext
Elementcounter = Elementcounter + 1
Wend
MsgBox E l e m e n t c o u n t e r & " elements found."
End Sub

And yet another scan criteria is added in our next procedure:

Sub T e s t S c a n F i 1 terG( 1
D i m myEnum As E l e m e n t E n u m e r a t o r
D i m m y F i l t e r As New E l e m e n t s c a n c r i t e r i a
D i m E l e m e n t c o u n t e r As L o n g
D i m m y C o l o r T a b l e As C o l o r T a b l e
D i m m y c o l o r As L o n g
Set myColorTable = ActiveDesignFile.ExtractColorTab1e
mycolor myColorTable.FindClosestColor(RGB(l92,
= 192, 192))
myFilter.ExcludeA11Types
myFi 1t e r . E x c l u d e A l 1 L e v e l s
myFilter.ExcludeA11Colors
myFi 1t e r . E x c l u d e A l 1 L i n e S t y l e s
myFilter.ExcludeA11Classes
m y F i l t e r . I n c l u d e T y p e msdElementTypeLineString
rnyFil t e r . I n c l u d e L i n e S t y l e A c t i v e D e s i g n F i l e . L i n e S t y l e s ( " ( Hidden ) " )
m y F i 1 t e r . I n c l u d e L e v e l A c t i v e D e s i g n F i l e . L e v e l s ( "SIDEWALK")
m y F i 1 t e r . I n c l u d e C o l o r myCol o r - 1
myFil t e r . I n c l u d e c l a s s msdElementClassPrimary
S e t myEnum = ActiveModelReference.Scan(myFi1ter)
W h i l e myEnum.MoveNext
Elementcounter = Elementcounter + 1
Wend
MsgBox E l e m e n t c o u n t e r & " elements found."
End Sub
320 I Chapter 16: Searching In Files I
Now we are adding the Classto our scan criteria.
Thus far we have excluded everything from our criteria and added in
only the criteria we wanted. When we ExcludeAllLevels,the number of
levels we exclude varies from file to file.
Now, lets look at each of the levels in our design file. One specific level
will not be added to our scan criteria and everything else will be added.

S u b T e s t S c a n F i 1t e r H ( )
D i m myEnum As E l e m e n t E n u m e r a t o r
D i m myFi 1 t e r As New E l e m e n t S c a n C r i t e r i a
D i m m y L e v e l As L e v e l
D i m E l e m e n t c o u n t e r As L o n g
myFi 1 t e r . E x c l u d e A l 1 L e v e l s
F o r Each m y L e v e l I n A c t i v e D e s i g n F i l e . L e v e 1 s
S e l e c t Case U C a s e ( m y L e v e l . N a m e )
C ase S ID EW A LK
Case E l s e
m y F i l t e r . I n c l udeLevel myLevel
End S e l e c t
Next
S e t myEnum = ActiveModelReference.Scan(myFi1ter)
W h i l e myEnum.MoveNext
Elementcounter = Elementcounter + 1
Wend
MsgBox E l e m e n t c o u n t e r & elements found.
End S u b

When dealing with our Elementscancriteria object, everything is


within the bounds of the criteria. Since we dont have the option to
remove a specific element type or level, etc., in the above example, we
remove all levels and then add back those levels that meet our criteria. In
the above example, we are adding all levels except for the SIDEWALK
level.
I Multiple Combinations of Criteria I 321

MULTIPLE
COMBINATIONS OF CRITERIA
Thus far we have dealt with elements matching specific criteria in each
procedure. What do we do if we want all cells on level Columnsand all
text elements on level Marks?Here are three ways to accomplish the
same task.

S u b TestScanFi 1 t e r J ( 1
D i m myElem As E l e m e n t
D i m myEnum As E l e m e n t E n u m e r a t o r
D i m myEnum2 As E l e m e n t E n u m e r a t o r
D i m m y F i l t e r As New E l e m e n t s c a n c r i t e r i a
D i m m y f i l t e r 2 As New E l e m e n t s c a n c r i t e r i a
D i m E l e m e n t c o u n t e r As Long
myFilter.ExcludeA11Types
myFi 1t e r . E x c l u d e A l 1 L e v e l s
myFil ter.IncludeType msdElementTypeSharedCel1
m y F i 1 t e r . I n c l u d e L e v e l A c t i v e D e s i g n F i 1 e . L e v e l s ( COLUMNS)
S e t myEnum = ActiveModelReference.Scan(myFi1ter)
W h i l e myEnum.MoveNext
Elementcounter = Elementcounter + 1
Wend

myFilter2.ExcludeAllTypes
myFi 1t e r 2 . E x c l u d e A l 1 L e v e l s
m y F i l t e r 2 . I n c l u d e T y p e msdElementTypeText
m y F i 1 t e r 2 . I n c l u d e L e v e l A c t i v e D e s i g n F i 1 e . L e v e l s ( MARKS)
S e t myEnum2 = ActiveModelReference.Scan(myFilter2)
W h i l e myEnum2.MoveNext
Elementcounter = Elementcounter + 1
Wend
MsgBox E l e m e n t c o u n t e r & elements found.
End S u b

We can use two different enumerator objects with two different scan
criteria objects. This is one way to deal with our current scenario. Are
there other ways we can accomplish the same goal?

S u b TestScanFi 1 t e r K ( 1
D i m myElem As E l e m e n t
D i m myEnum As E l e m e n t E n u m e r a t o r
322 I Chapter 16: Searching In Files I
D i m myFi 1 t e r As New E l e m e n t S c a n C r i t e r i a
D i m m y C o l l e c t i o n As New C o l l e c t i o n
myFi 1 t e r . E x c l u d e A l 1 T y p e s
myFi 1 t e r . E x c l u d e A l 1 L e v e l s
myFi 1 t e r . I n c l u d e T y p e msdEl e m e n t T y p e S h a r e d C e l 1
myFilter.IncludeLeve1 ActiveDesignFile.Levels("COLUMNS")
S e t myEnum = ActiveModelReference.Scan(myFi1ter)
W h i l e myEnum.MoveNext
S e t myElem = myEnum.Current
my C o 1 1 e c t io n . Add my E 1 em
Wend

myFi 1 t e r . R e s e t
myFi 1 t e r . E x c l u d e A l 1 T y p e s
myFi 1 t e r . E x c l u d e A l 1 L e v e l s
myFi 1 t e r . I n c l u d e T y p e msdEl e m e n t T y p e T e x t
myFilter.IncludeLeve1 ActiveDesignFile.Levels("MARKS")
S e t myEnum = ActiveModelReference.Scan(myFi1ter)
W h i l e myEnum.MoveNext
S e t myElem = myEnum.Current
my C o 1 1 e c t io n . Add my E 1 em
Wend
MsgBox m y C o l 1 e c t i o n . C o u n t & " e l ements f o u n d . "

End S u b

This is another way to accomplish the same goal. We apply two separate
criteria. As we move through each enumerator, we add the element in
the enumerator to a custom collection. This allows us to work with a
single collection of objects after each combination of criteria is applied.
I Multiple Combinations of Criteria I 323

Cache ElementCachelElementCac
Cachelndex 18 Long
Class msdEIementCIassPrimary MsdEIementCIass
Color 0 Long
DateLastModified #9L?OL?OO55:26:39PM# Date
FilePosition 4000017 Long
GraphicGroup 0 Long
HasAnyTags False Boolean
Adding a watch to lnDisplay Set True Boolean

the variable IsComponentElement False


IsFromAttachment False
Boolean
Boolean
myCollection IsGraphical True Boolean
shows something IsHidden False Boolean
IsLinear False Boolean
like this: IsLocked False Boolean
IsModified True Boolean
lsNew True Boolean
IsSnappable True Boolean
IsValid True Boolean
Level Levelhevel
LineStyle LineStylehineSty le
Lineweight 0 Long
ModelReference ModelReferencehlodelRel
Subtype <Attemptingto perform a non-! MsdElementSubtype
Type msdElementTypeSharedCell MsdElementType
URL String
URLTiile String
iiem 2 VariantmbjecilElement
iiem 3 VariantmbjecilElement

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 T e s t S c a n F i 1 t e r M (
Dim myEnum As ElementEnumerator
Dim myFilter As New Elementscancriteria
Dim myGroup As NamedGroupElement
Set myGroup = A c t i v e M o d e l R e f e r e n c e . A d d N e w N a m e d G r o u p ( " G r o u p A " )
myFilter.ExcludeA11Types
myFi 1 ter. Excl udeAl1 Levels
myFil ter.IncludeType msdElementTypeSharedCel1
myFil ter. IncludeLevel ActiveDesignFile Leve s ( CO LU M N S " "

Set myEnum = ActiveModelReference.Scan myFi ter)


While myEnum.MoveNext
myGroup.AddMember myEnum.Current
Wend
324 I Chapter 16: Searching In Files I
myFi 1 t e r . Reset
myFi 1 t e r . E x c l u d e A l 1 Types
myFi 1 t e r . E x c l u d e A l 1 L e v e l s
myFi 1 t e r . I n c l udeType msdEl ementTypeText
myFilter.IncludeLeve1 ActiveDesignFile.Levels("MARKS")
S e t myEnum = ActiveModelReference.Scan(myFi1ter)
W h i l e myEnum.MoveNext
myGroup.AddMember myEnum.Current
Wend
myGroup. Rewri t e
MsgBox myGroup.MembersCount & " elements found."
End Sub

.
REVIEWINGTHREE
COLLECTION METHODS
Each of the three methods described above have their advantages and
disadvantages. For the sake of discussion, we will refer to the methods as
multi-criteria, collection, and group.
The multi-criteria method provides a straightforward and simple way to
get groups of criteria in their own individual enumerators. One benefit
to doing things this way is that we have our individual groups of criteria
in their own distinct groups. This allows us to work with each group
separately if desired. The primary disadvantage is that these individual
groups make it more difficult to work with the elements in each group as
a whole.
The collection method uses only one Scancriteria object and places all
objects found into a single custom VBA collection. Doing so allows us to
use For Each ... Next statements on the entire collection, remove items
from the collection, etc.
The group method may provide the best possible results. Each item is
placed into a single container. This gives us the same benefit as using a
collection. The real benefit to using groups is that when we use
"myGroup.Rewrite", the group is added to the design file and can be
used by the user with other standard Microstation commands and
I Scan Criteria Methods I 325

functionality. If we do not rewrite the group, the elements added to the


group do not get added to the group in the design file even though the
group itself is in the design file. So, if we want to use a group without
rewriting it to the design file, we should remove the group after we have
completed our programming tasks.

SCAN CRITERIA METHODS


The code we have written in this chapter has used several methods of
the Elementscancriteria Object. Here is a comprehensive listing of the
methods:

Sub Excl udeAl1 C1 asses( )


Sub Excl udeAl1 Colors( )
Sub Excl udeAl1 Levels( )
Sub Excl udeAl1 Li neStyl es( )
Sub Excl udeAl1 LineWeights()
Sub Excl udeAl1 Subtypes( )
Sub Excl udeAl lTypes( )
Sub Excl udeGraphical()
Sub Excl udeNonGraphica1 ( )
Sub IncludeClass(ElemC1ass As MsdElementClass)
Sub IncludeColor(Color1ndex As Long)
Sub Incl udeLevel (Level As Level )
Sub IncludeLineStyle(LineSty1e As Linestyle)
Sub IncludeLineWeight(LineWeight As Long)
Sub IncludeOnlyCell(CellName As String)
Sub IncludeOnlyFilePositionRange(Min As Long, Max As Long)
Sub IncludeOnlyGraphicGroup(GraphicGroupNumber As Long)
Sub Incl udeOnlyHole()
Sub IncludeOnlyInvisibleO
Sub Incl udeOnlyLocked()
Sub IncludeOnlyModifiedO
Sub IncludeOnlyModifiedRange(Min As Date, [Max As Date])
Sub Incl udeOnlyNew()
Sub Incl udeOnlyNonPlanar()
Sub IncludeOnlyNonSnappableO
Sub Incl udeOnlyOld()
Sub Incl udeOnlyPlanar()
Sub IncludeOnlySnappableO
326 I Chapter 16: Searching In Files I
Sub I n c l u d e O n l y S o l i d O
Sub I n c l u d e O n l y U n l o c k e d O
Sub I n c l u d e O n l y U n m o d i f i e d O
Sub IncludeOnlyUserAttribute(UserAttribute1D As L o n g )
Sub I n c l u d e O n l y V i s i b l e O
Sub IncludeOnlyWithinRange(Range As R a n g e 3 d )
Sub I n c l u d e S u b t y p e ( L 0 n g As L o n g )
Sub I n c l u d e T y p e ( T y p e As M s d E l e m e n t T y p e )
Sub R e s e t 0

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 T e s t S c a n F i 1 t e r N ( )
D i m myEnum As E l e m e n t E n u m e r a t o r
D i m m y F i 1 t e r As New E l e m e n t S c a n C r i t e r i a
D i m m y G r o u p As N a m e d G r o u p E l e m e n t
D i m myRange As Range3d
S e t 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.High.Z = 0
myFilter.Include0nlyWithinRange myRange
S e t myEnum = ActiveModelReference.Scan(myFi1ter)
W h i l e myEnum.MoveNext
myGroup.AddMember m y E n u m . C u r r e n t
Wend
myGroup. Rewri t e
MsgBox m y G r o u p . M e m b e r s C o u n t & " elements 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 L0w.Z
and a High.Z value if we are working on 3D files.
I Review I 327

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.
17 Interactive Modification

User interaction can be helpful when modifymg files and elements in


VBA. When our programs are designed well, they are powerful and
flexible.

In this Chapter:
Giving users feedback and information
Working with selection sets
Getting user input
Using the send command
Employing modeless dialog boxes
Applying some real-world applications
Interacting with MDL applications

GIVINGUSERS FEEDBACK
AND lNFORMATlON
When we are working with Microstation in any capacity, three distinct
areas at the bottom of the Microstation window give us information and
feedback.

329
330 I Chapter 17: Interactive Modification I
These areas are called the command, prompt, and status areas.
~~~~~~~ ~F~~~~ ~~~~~~

When we begin the Place SmartLine command, we see the command


and the first prompt associated with this command. We are prompted to
Enter first vertex: After we click the first vertex, we are prompted to
Enter next vertex or reset to complete: The Status area gives us general
feedback on the results of selections and other commands.
Lets see how we can work with these areas to give our users similar
feedback and information as they use our programs.

Sub TestShowCommandO
ShowCommand D r a w a L i n e
ShowPrompt S e l e c t F i r s t P o i n t :
ShowStatus Draw L i n e b y s e l e c t i n g two p o i n t s .
End Sub

Three methods are used to show the text we want to display in the
command, prompt, and status areas of Microstation. Even though the
user can change the size of the command/prompt area, make sure that
commands and prompts are visible without requiring users to stretch
the area wider. Commands and prompts are not meant to provide
comprehensive instructions, but rather, general guidelines.

Sub TestShowTempMessageO
ShowTempMessage r n s d S t a t u s B a r A r e a L e f t , Message L e f t .
ShowTempMessage r n s d S t a t u s B a r A r e a M i d d l e , M e s s a g e M i d d l e .

End Sub
I Giving Users Feedback and Information I 331

Another way we can provide feedback to the user is by sending a


Temporary Message: We have the option of placing the message in the
Left Area or the Middle Area. Messages placed in the middle area
also appear in the Message Center.
Sub ShowTempMessage(AreaAs MsdStatusBarArea,
Message As String, [Details As String])
Here is the declaration for ShowTempMessage. It has one optional
parameter, Details: When we provide a value for this parameter and we
have specified msdStatusBarAreaMiddle as the location for the
message, the detail we provide displays in the Message Center. This is an
excellent way to provide a more lengthy message to the user if needed.

Sub TestShowTempMessageCenterO
ShowTempMessage m s d S t a t u s B a r A r e a M i d d l e , C h a n g e s made t o f i l e : , -

C h a n g e s w e r e made t o t h e f i l e C : \ t e s t a . d g n . & -

T h e s e c h a n g e s w e r e made by t h e m a c r o & -

T e s t S h ow Temp Me s s a g e C e n t e r .

End S u b
332 I Chapter 17: Interactive Modification I

Circle, Level Default


Shaoe. Level Default

The next feedback method we will look at is the Show E r r o r method. The
text we supply with this method displays in the command/prompt area.

Sub TestShowError()
ShowError "Selection o f Cell Failed."
End Sub

.
WORKING
WITHSELECTIONSETS
Users can select elements in their files through a variety of methods.
Once selected, we can make modifications to the selected elements by
using the GetSel ectedEl ements method.

Sub TestSel ecti onSetA( )


Dim myElement As Element
Dim myElemEnum As ElementEnumerator
Set myElemEnum = ActiveModelReference.GetSelectedElements
While myElemEnum.MoveNext
Set myEl ement = myEl emEnum. Current
myElement. Level = ActiveModel Reference. Levels(
"A-FURN-FREE")
Wend
End Sub
We used the ElementEnumerator in a previous chapter. In this example,
we get the selected elements and change the level of each element one-
by-one. Let's look carefully at the code. Are we missing anything?

Sub TestSelectionSetB()
Dim myElement As Element
Dim myElemEnum As ElementEnumerator
Set myElemEnum = ActiveModelReference.GetSelectedElements
I Working With Selection Sets I 333

Whi 1 e myEl emEnum.MoveNext


Set myElement = myElemEnum.Current
myElement. Level = ActiveModel Reference. Levels("A-FURN-FREE")
myEl ement. R e w r i t e
Wend
End Sub
If we do not rewrite the element to the design file, element
modifications are not persistent. This is critical. You could spend a great
deal of time debugging code only to find that changes made to elements
are not reflected in your files. Any changes made to elements in files
must be rewritten back to the file or they are not permanent. This is by
design.

Sub TestSelectionSetC(1
Dim mysettings A s Settings
Set mysettings = Application.ActiveSettings
If MsgBox("Change Selection to Color & rnySettings.Color & " ? " .
" ~

vbYesNo) = vbYes Then


Dim myElement A s Element
Dim myElemEnum A s ElementEnumerator
Set myElemEnum = ActiveModel Reference.GetSelectedElements
While myElemEnum.MoveNext
Set myElement = myElemEnum.Current
myElement.Color = mySettings.Color
myElement.Rewrite
Wend
End If
End S u b
TestSel ectionSetC 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 I Chapter 17: Interactive Modification I

GETTINGUSERINPUT
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 TestCadInputA()
Dim myCIQ As CadInputQueue
Dim myCIM As CadInputMessage
Dim I A s Long
Set myCIQ = CadInputQueue
For I = 1 T o 10
Set myCIM = myCIQ.GetInput
Debug.Print myCIM.InputType
Next 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 TestCadInputB()
Dim myCIQ As CadInputQueue
Dim myCIM As CadInputMessage
Dim I A s Long
Dim pt3Selection As Point3d
Set myCIQ = CadInputQueue
For I = 1 T o 10
Set myCIM = myCIQ.GetInput(msdCad1nputTypeDataPoint)
pt3Selection = myCIM.Point
Debug.Print pt3Selection.X & " , & pt3Selection.Y
"

Next I
End Sub
I Getting User Input I 335

The CadInputQueue captures a number of different types of inputs.


When we use the GetInput method we can specify which type of inputs
we want to capture. In the above example we are restricting the capture
to data point entries. Since we know we are getting a point, we can use
the point property of the CadInputMessage object and print the X, Y,
and Z elements of the point to the Debug window (Immediate Window).
Lets continue to build on our TestCadInput macros. In the next
example we will capture points and resets.

Sub TestCadInputC( 1
Dim myCIQ A s CadInputQueue
Dim myCIM A s CadInputMessage
Dim I As Long
Dim pt3Selection A s Point3d
Set myCIQ = CadInputQueue
For I = 1 To 10
Set myCIM = myCIQ.GetInput(msdCadInputTypeDataPoint, -
msdCadInputTypeReset)
Select Case myCIM.InputType
Case msdCadInputTypeDataPoint
pt3Selection = myCIM.Point
Debug.Print pt3Selection.X & , & pt3Selection.Y

Case msdCadInputTypeReset
Exit For
End Select
Next I
End Sub
Now, our macro captures up to ten input points or until a reset is
initiated by the user. We use Exi t For to exit out of the loop when a reset
is detected.
We have introduced DataPoint and Reset input types, so what other
types are available to us?

msdCadInputTypeCommand = 1
msdCadInputTypeReset = 2
msdCadInputTypeDataPoint = 3
msdCadInputTypeKeyin = 4
msdCadInputTypeAny = 5
msdCadInputTypeUnassignedCB = 6
I Chapter 17: Interactive Modification I
When we begin capturing input using the CadInputQueue, our program
listens to each of the inputs, then the results of the inputs is entirely in
the hands of our program. For example, if we begin capturing inputs,
selecting a command from a toolbar sends the command information to
our queue but Microstation does not begin acting on the command
immediately.

Sub TestCadInputD()
D i m m y C I Q As C a d I n p u t Q u e u e
D i m m y C I M As C a d I n p u t M e s s a g e
D i m I As Long
D i m p t 3 S e l e c t i o n As P o i n t 3 d
S e t myCIQ = CadInputQueue
F o r I = 1 To 1 0
S e t myCIM = myCIQ.GetInput
S e l e c t Case m y C I M . I n p u t T y p e
Case msdCadInputTypeCommand
D e b u g . P r i n t "Command" & v b T a b & rnyC1M.CornrnandKeyin
Case r n s d C a d I n p u t T y p e R e s e t
E x i t For
Case msdCadInputTypeDataPoint
pt3Selection = myCIM.Point
Debug.Print " P o i n t " & vbTab & pt3Selection.X & vbTab & -

p t 3 S e l e c t i o n . Y & vbTab & -

p t 3 S e l e c t i o n . Z & vbTab & -

rnyCIM.View.Index & vbTab & -

myC1M.ScreenPoint.X & vbTab & ~

myC1M.ScreenPoint.Y & vbTab & ~

myC1M.ScreenPoint.Z
Case r n s d C a d I n p u t T y p e K e y i n
Debug.Print " K e y i n " & vbTab & myCIM.Keyin
Case r n s d C a d I n p u t T y p e A n y
Debug.Print "Any"
Case msdCadInputTypeUnassignedCB
D e b u g . P r i n t "UnassignedCB" & vbTab & ~

myCIM.CursorButton
End S e l e c t
Next I
End Sub
I Getting User Input I 337

This procedure captures ten inputs or captures until a reset is detected.

Point 11581.8836494914 27463.2962386063 0 1 377 579 0


Point 9599.68844328587 28602.2371305697 0 1 196 475 0
Command PLACE S M A R T L I N E
Command PLACE BLOCK I C O N
Command CGPLACE C I R C L E I C O N
Keyin bogus k e y i n
Point 10796.1239475839 31518.0353275433 0 1 168 238 0
Point 10664.7076908189 30833.5756568922 0 1 144 363 0
Command MDL KEYIN l v l m a n g r l e v e l m a n a g e r d i a l o g o p e n
Point 11195.8483952442 31019.7486873093 0 1 241 329 0

The results of running this procedure with a variety of inputs.

Points
The points selected gives us much more than the X, Y, and Z locations in
Microstation. 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.

Unassigned Cursor Buttons


An unassigned cursor button generates an UnassignedCB input. We use
the CursorButton property of the message to retrieve which cursor
button was used.
338 I Chapter 17: Interactive Modification I

Reset
The Reset Input is triggered when the user initiates a reset. For example,
clicking the right mouse button initiates a reset when the user is asked to
select a point.

SOME REAL-WORLDAPPLICATIONS
Now that we have an understanding of how these inputs work, lets put
them to work in some real-world examples.

S u b TestCadInputE()
Dim myCIQ As CadInputQueue
Dim myCIM As CadInputMessage
Dim pt3Start As Point3d
Dim pt3End As Point3d
Dim myLine As LineElement
Set myCIQ = CadInputQueue
Set myCIM = rnyCIQ.GetInput(rnsdCadInputTypeDataPoint, -
rnsdCadInputTypeReset)
Select Case rnyCIM.InputType
Case msdCadInputTypeReset
Exit S u b
Case msdCadInputTypeDataPoint
pt3Start = rnyCIM.Point
End Select
Set myCIM = rnyCIQ.GetInput(rnsdCadInputTypeDataPoint, -
msdCadInputTypeReset)
Select Case myCIM.InputType
Case msdCadInputTypeReset
Exit S u b
Case msdCadInputTypeDataPoint
pt3End = rnyCIM.Point
End Select
Set myLine = CreateLineElementZ(Nothing, pt3Start, pt3End)
ActiveModel Reference.AddE1 ement myLine
myLi ne. Redraw
End S u b
TestCadInputE allows the user to select two points. A line is then
drawn between these two points. A careful examination of the code, and
I Some Real-World Applications I 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 TestCadInputF( 1
D i m myCICl As C a d I n p u t Q u e u e
D i m myCIM As C a d I n p u t M e s s a g e
D i m p t 3 S t a r t As P o i n t 3 d
D i m p t 3 E n d As P o i n t 3 d
D i m m y L i n e As L i n e E l e m e n t
S e t myCICl = CadInputQueue
ShowCommand " T w o - P o i n t L i n e "
ShowPrompt " S e l e c t F i r s t P o i n t : "
S e t myCIM = myCIQ.GetInput(msdCadInputTypeDataPoint, ~

msdCadInputTypeReset.1
S e l e c t Case m y C I M . I n p u t T y p e
Case m s d C a d I n p u t T y p e R e s e t
ShowPrompt " "

" "
S h ow C o mm a n d
ShowStatus "Two-Point L i n e Reset."
E x i t Sub
Case m s d C a d I n p u t T y p e D a t a P o i n t
pt3Start = myCIM.Point
End S e l e c t
ShowPrompt " S e l e c t Second P o i n t : "
S e t myCIM = myCIQ.GetInput(msdCadInputTypeDataPoint, ~

msdCadInputTypeReset.1
S e l e c t Case m y C I M . I n p u t T y p e
Case m s d C a d I n p u t T y p e R e s e t
ShowPrompt " "

" "
S h ow C o mm a n d
ShowStatus "Two-Point L i n e Reset."
E x i t Sub
Case m s d C a d I n p u t T y p e D a t a P o i n t
pt3End = myCIM.Point
End S e l e c t
Set myLine = CreateLineElementZ(Nothing, p t 3 S t a r t . pt3End1
ActiveModel Reference.AddElement myLine
m y l i n e . Redraw
340 I Chapter 17: Interactive Modification I
ShowPrompt " "

" "
S h ow C omm a n d
Showstatus "Two-Point Line Drawn."
End Sub
Now, when this macro is run, the user is prompted at each step.
The CadInputQueue can be used for more than just capturing user
input. We can use it to execute commands as well. Here is one example:

Sub TestCadInputH()
Dim myCIQ As CadInputQueue
Dim myCIM As CadInputMessage
Dim pt3Start As Point3d
Dim pt3End As Point3d
Dim myLine As LineElement
Dim S e l E l e m s O As Element
Set myCIQ = CadInputQueue
Set myCIM = rnyCIQ.GetInput(rnsdCadInputTypeDataPoint, -

rnsdCadInputTypeReset)
Select Case rnyCIM.InputType
Case msdCadInputTypeReset
Exit Sub
Case msdCadInputTypeDataPoint
pt3Start = rnyCIM.point
End Select
Set myCIM = rnyCIQ.GetInput(rnsdCadInputTypeDataPoint, -

msdCadInputTypeReset)
Select Case myCIM.InputType
Case msdCadInputTypeReset
Exit Sub
Case msdCadInputTypeDataPoint
pt3End = rnyCIM.point
End Select
CadInputQueue.SendDragPoints pt3Start, pt3End
SelElems = -
A c t i veModel R e f e r e n c e . G e t S e l e c t e d E l e m e n t s . B u i 1 d A r r a y F r o m C o n t e n t s
If MsgBox("Are y o u sure y o u want to delete & " ~

UBound(SelE1ems) + 1 & Elements?", vbYesNo) "

= vbYes Then

Cad1nputQueue.SendCornrnand "DELETE"
End If
End Sub
I Some Real-World Applications I 341

In this example we used the selected points with the SendDragPoints


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 P o i n t s B y L i n e O A s Point3dO
Dim myCIQ As CadInputQueue
Dim myCIM As CadInputMessage
Dim pt3Start As Point3d
Dim pt3End As Point3d
Dim selPts(0 To 1) As Point3d
Set myCIQ = CadInputQueue
Set myCIM = myCIQ.GetInput(msdCadInputTypeDataPoint, -

msdCadInputTypeReset)
Select Case myCIM.InputType
Case msdCadInputTypeReset
Err.Raise -12345
Exit Function
Case m s d C a d I n p u t T y p e D a t a P o i n t
pt3Start = myCIM.point
End Select
CadInputQueue.SendCommand PLACE LINE
C a d 1 n p u t Q u e u e . S e n d D a t a P o i n t pt3Start
Set myCIM = myCIQ.GetInput(msdCadInputTypeDataPoint, -

msdCadInputTypeReset)
Select Case myCIM.InputType
Case msdCadInputTypeReset
342 I Chapter 17: Interactive Modification I
E r r . R a i s e -12346
E x i t Function
Case msdCadInputTypeDataPoint
pt3End = myCIM.point
End S e l e c t
selPts(0) = pt3Start
selPts(1) = pt3End
PointsByLine = selPts
End F u n c t i o n

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 P o i n t s By L i 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 TestCadInputJ()
On E r r o r GoTo e r r h n d
D i m s e l P t s 0 As P o i n t 3 d
selPts = PointsByLine
CadInputQueue.SendReset
CommandState.StartDefaultCommand
Debug.Print selPts(O1.X & " , " & selPts(O1.Y & ", " & selPts(01.Z
Debug.Print s e l P t s ( l ) . X & " , " & selPts(l1.Y & " , " & selPts(l1.Z
E x i t Sub

errhnd:
CadInputQueue.SendReset
CommandState.StartDefaultCommand
S e l e c t Case E r r . N u m b e r
Case - 1 2 3 4 5
'Start Point not selected
MsgBox " S t a r t P o i n t n o t s e l e c t e d . " , vbcritical
Case - 1 2 3 4 6
'End P o i n t n o t s e l e c t e d
MsgBox " E n d P o i n t n o t s e l e c t e d . " , vbcritical
I Some Real-World Applications I 343

End S e l e c t
End Sub

We use P o i n t s B y L i n e to get two points. Notice the S e n d R e s e t and


S t a r t D e f a u l tcornrnand 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 Po in t s By L in e function:

Sub TestCadInputK( 1
On E r r o r GoTo e r r h n d
D i m s e l P t s 0 As P o i n t 3 d
D i m p t 3 T e x t P t As P o i n t 3 d
D i m m y T e x t As T e x t E l e m e n t
D i m r o t M a t r i x As M a t r i x 3 d
sel Pts = PointsByLine
Cad1nputQueue.SendReset
CommandState.StartOefaultCommand
S e t myText = CreateTextElernentl(Nothing, " S t a r t " , selPts(0). rotMatrix)
ActiveModel Reference.AddElement myText
Set myText = CreateTextElementl(Nothing, "End", s e l P t s ( l ) , r o t M a t r i x )
ActiveModel Reference.AddElement myText
pt3TextPt.X = selPts(O).X + (selPts(l).X - selPts(O).X) / 2
pt3TextPt.Y = selPts(O).Y + (selPts(l).Y - selPts(O).Y) / 2
pt3TextPt.Z = selPts(O).Z + ( s e l P t s ( l ) . Z - selPts(O).Z) / 2
S e t myText = CreateTextElernentl(Nothing. "Mid". pt3TextPt, r o t M a t r i x )
ActiveModel Reference.AddElement myText
E x i t Sub
errhnd:
Cad1nputQueue.SendReset
CommandState.StartOefaultCommand
S e l e c t Case E r r . N u m b e r
Case - 1 2 3 4 5
'Start Point not selected
MsgBox " S t a r t P o i n t n o t s e l e c t e d . " , vbcritical
Case - 1 2 3 4 6
'End P o i n t n o t s e l e c t e d
MsgBox " E n d P o i n t n o t s e l e c t e d . " , vbcritical
I Chapter 17: Interactive Modification I
End Select
End Sub
The framework is the same as the previous example. We use our new
Po in t s By L i n e 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
Microstation:

Start

Here is one more function that simulates the PLACE BLOCK


command, allowing the user to stretch out a rectangle instead of a line.

Function P o i n t s B y R e c t a n g l e O As P o i n t 3 d O
Dim myCIQ As CadInputQueue
Dim myCIM As CadInputMessage
Dim pt3Start As Point3d
Dim pt3End As Point3d
Dim selPts(0 T o 1) As Point3d
Set myCIQ = CadInputQueue
Set myCIM = myCIQ.GetInput(msdCadInputTypeDataPoint,
msdCadInputTypeReset)
Select Case myCIM.InputType
Case msdCadInputTypeReset
Err.Raise -12345
Exit Function
Case msdCadInputTypeDataPoint
pt3Start = myCIM.point
End Select
Cad1nputQueue.SendCommand PLACE BLOCK
I Some Real-World Applications I 345

Cad1nputQueue.SendDataPoint pt3Start
Set myCIM = myCIQ.GetInput(msdCadInputTypeDataPoint, -

msdCadInputTypeReset.1
Select Case myCIM.InputType
Case msdCadInputTypeReset
Err.Raise -12346
Exit Function
Case msdCadInputTypeDataPoint
pt3End = myCIM.point
End Select
sel Pts(0) = pt3Start
selPts(1) = pt3End
PointsByRectangle = selPts
End Function
Andnowaprocedure that uses P o i n t s B y R e c t a n g l e :

Sub TestCadInputL( 1
On Error GoTo errhnd
Dim s e l P t s 0 A s Point3d
sel Pts = PointsByRectangle
Cad1nputQueue.SendReset
CommandState.StartDefaultCommand
Debug.Print selPts(O1.X & ", " & selPts(O).Y & ", " & selPts(O).Z
Debug.Print selPts(l1.X & ". " & selPts(l).Y & ". " & selPts(l).Z
Exit Sub

errhnd:
Cad1nputQueue.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
346 I Chapter 17: Interactive Modification I

Gie

SEYi

TestCadInputL does not do anything fancy. It just displays the points


selected in the Immediate Window. Lets make better use of
Po in t s By Recta n g 1 e by using the selected points as part of a scan criteria
in selecting cells in a file.

Sub TestCadInputM()
On E r r o r GoTo e r r h n d
D i m s e l P t s 0 As P o i n t 3 d
D i m L i n e P t s ( 0 To 1) As P o i n t 3 d
D i m L i n e E l e m As L i n e E l e m e n t
D i m myESC As New E l e m e n t s c a n c r i t e r i a
D i m myRange As Range3d
D i m myElemEnum As E l e m e n t E n u m e r a t o r
D i m myElem As E l e m e n t
D i m F F i l e As L o n g
D i m m y C e l 1 H e a d e r As C e l l E l e m e n t
sel Pts = PointsByRectangl e
Cad1nputQueue.SendReset
CommandState.StartDefaultCommand
myRange = Range3dFromPoint3dPoint3d(sel P t s ( 0 ) . sel Pts(1))
myESC. E x c l u d e A l 1 T y p e s
m y E S C . I n c l u d e T y p e msdElementTypeCellHeader
myESC.IncludeOnlyWithinRange myRange
S e t myElemEnum = ActiveModelReference.Scan(myESC)
I Some Real-World Applications I 347

FFile = FreeFile
Open "C:\MicroStation VBA\CellExport.txt" For Output As BFFile
Print #FFi le, ActiveDesignFi 1 e. Name
Whi 1 e myEl emEnum.MoveNext
Set myElem = myElemEnum.Current
Set myCel1 Header = myEl em
Print BFFile, myCellHeader.Name & vbTab & -
myCellHeader.0rigin.X & vbTab & -
myCellHeader.0rigin.Y & vbTab & ~

myCel1 Header. Ori gi n. Z


Wend
C1 ose BFFi 1 e
Exit Sub

errhnd:
CadInputQueue.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 bffice.dan


PART
output for the GWALL
PART
office.dgn file URINAL
PART
installed with URINAL
nP&RT
DPART
Microstation: PDOORR 14517.3074154912 15917.6804376836 0
RAIL2 16233.3074154912 16991.6774376836 0
RAIL1 16233.3074154912 15851.6804376836 0

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 w
ill
be output to the text file.
348 I Chapter 17: Interactive Modification I

USINGSENDCOMMAND
Thus far we have used Sendcommand with DELETE: PLACE LINE:
and PLACE BLOCK.Even though these commands may look familiar
to some readers, they may be foreign to others. Each time a menu item is
selected or toolbar button clicked, a command is issued to Microstation.
How do we know what these commands are? Good question.
The Microstation VBA macro recorder can help us to discover
command names and how they are used. Lets try recording a few
macros to demonstrate this.
1 From the VBA Project Manager, select the VBA Project in which we
are currently working and then click the record button.

2 Now, select the Line


L Place SrnartLine
Command from the toolbar as
shown: 3 Place Multi-line

3 Place Line begins by asking


for points between which to draw lines. Select two points in
Microstation and then click the right mouse button to issue a reset.
4 Next, stop recording the macro by clicking the Stop Record
button.

5 After macro recording has stopped, return to the VBA environment


to see the new macro. The macros are named automatically so the
names may vary from computer to computer.
The results of this recorded macro should look similar to this:
I Using Sendcommand I 349

Sub Macro10
Dim startpoint As Point3d
Dim point As Point3d, point2 As Point3d
Dim lngTemp As Long

Start a command
CadInputQueue.SendCommand CGPLACE L I N E CONSTRAINED

Coordinates are i n master units


startP0int.X = 16735.231975
startP0int.Y = 33020.733029
startP0int.Z = O#

Send a data point to the current command


p0int.X = startP0int.X
p0int.Y = startP0int.Y
p0int.Z = startP0int.Z
Cad1nputQueue.SendDataPoint point, 1

p0int.X = startP0int.X + 1985.401024


p0int.Y = startP0int.Y - 610.892623
p0int.Z = startP0int.Z
CadInputQueue.SendDataPoint point, 1

Send a reset to the current command


Cad1nputQueue.SendReset

CommandState.StartDefaultCommand
End S u b
This recorded macro reveals a command of CGPLACE LINE
CONSTRAINED. The coordinates shown are those selected in
Microstation as the macro was being recorded. Lets copy and paste the
recorded macro and modify it as follows:

S u b Macrol-modi f i edA( )
Dim point As Point3d
CadInputQueue.SendCommand CGPLACE L I N E CONSTRAINED

p0int.X = 0: p0int.Y = 0: p0int.Z = 0


CadInputQueue.SendDataPoint point, 1
p0int.X = 4: p0int.Y = 5: p0int.Z = 6
Cad1nputQueue.SendDataPoint point, 1
350 I Chapter 17: Interactive Modification I
CadInputQueue.SendReset
CommandState.StartDefaultCommand
End S u b

We have now stripped down this macro to the bare essentials. The
coordinates for the line have been replaced with (0, 0,O) and (4 , 5 , 6 ).
Let's record another macro. This time we will record drawing a Block
(rectangle).

Sub Macro20
D i m s t a r t p o i n t As P o i n t 3 d
D i m p o i n t As P o i n t 3 d , p o i n t 2 As P o i n t 3 d
D i m l n g T e m p As L o n g

' S t a r t a command
CadInDutQueue.SendCommand "PLACE BLOCK I C O N "

' Coordinates are i n master u n i t s


startP0int.X = 3.196418
startP0int.Y = 6.071205
startP0int.Z = O#

' Send a d a t a p o i n t t o t h e c u r r e n t command


p0int.X = startP0int.X
p0int.Y = startP0int.Y
p0int.Z = startP0int.Z
CadInputQueue.SendDataPoint p o i n t , 1

p0int.X = startP0int.X + 2.537984


p0int.Y = startP0int.Y - 0.882104
p0int.Z = startP0int.Z
CadInputQueue.SendDataPoint p o i n t , 1

CommandState.StartDefaultCommand
End S u b

Here is a stripped-down and modified version of Macro2.

S u b Macro2Lmodi f i edA( 1
D i m p o i n t As P o i n t 3 d
CadInputQueue.SendCommand "PLACE BLOCK I C O N "

p0int.X = 0
p0int.Y = 0
I Using Sendcommand I 351

p0int.Z = 0
CadInputQueue.SendDataPoint point, 1
p0int.X = p0int.X + 2.5
p0int.Y = p0int.Y - 0.75
CadInputQueue.SendDataPoint point, 1
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 Macro2Lmodi f i edB( )


Dim point As Point3d
Dim myCIQ As CadInputQueue
Dim myCIM As CadInputMessage
Set myCIQ = CadInputQueue
Set myCIM = myCIQ.GetInput(msdCad1nputTypeDataPoint)
point = myCIM.point
CadInputQueue. Sendcommand "PLACE BLOCK ICON "

CadInputQueue.SendDataPoint point, 1
p0int.X = p0int.X + 2.5
p0int.Y = p0int.Y - 0.75
CadInputQueue.SendDataPoint point, 1
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 TestCadInputN( 1
Dim myCIQ As CadInputQueue
Dim myCIM As CadInputMessage
Dim I As Long
Set myCIQ = CadInputQueue
F o r I = 1 To 10
Set myCIM = myCIQ.GetInput(msdCad1nputTypeCommand)
352 I Chapter 17: Interactive Modification I
Debug.Print myCIM.CommandKeyin
Next I
End Sub
T e s t Ca d I n p u t N captures ten
commands. This is
CGPLACE LINE CONSTRAINED
different from recording PLACE BLOCK ICON
macros in that we do not ~ ~ ~ ~ ~ ICON ~ C ~ ~ R C L E
get all of the other input, Attach Tags
WORDPROCESSOR PLACE TEXT ICON
such as point selections, PLACE CELL ICON
etc. The only thing we MEASURE DISTANCE ICON
DIMCREATE ELEMENT
capture is the command PLACE FENCE ICON
name.
One additional method of determining command names should be
mentioned.

digitizer palette
dimcreate particletrace
dimension plot
dimstyle popset
displayset preview

dialog openfile
dialog drawingscale open
dialog drawingscale
delete
erase
bogus keyin

The Key-in dialog opens by selecting Key-in from the Microstation


Utilities menu. Items can be selected from the list boxes to construct the
appropriate key-in. The image shown tells us we can use DIALOG
OPENFILE as a command. Lets try it.

Sub TestMessageA( 1
CadInputQueue.SendCommand DIALOG OPENFILE
End Sub
I Modeless Dialog Boxes I 353

Running the TestMessageA macro shows us that DIALOG OPENFILE


is indeed a legitimate command. The Open File dialog box displays and
the user can select a file to open.

MODELESS
DIALOG
BOXES
InputBoxes and MessageBoxes allow the user to interact with our code.
Their functionality is somewhat limited, however. When our goal can be
accomplished with a MessageBox, it should be used. But when we need a
richer interface or more dynamic interaction with the user, we need to
use Forms.
The next four examples are on the CD accompanying this book. Import
them one at a time by using the VBA menu File > Import File and
selecting the appropriate file from the CD. This imports a new form into
the active VBA project.

frmMatchProperties.f rm
The first form,
frmMatchProperties.
frm,looks like this:
The form looks
simple enough. We
have a few command
buttons, a couple of
frames, a handful of
check boxes, a label,
and four text boxes.
Before we look at the
code behind the
controls, lets discuss the programs desired functionality.
354 I Chapter 17: Interactive Modification I
Desired Functionality
1 The user can select a Source element in Microstation. After the
element is selected, the Select button is clicked and four properties
are extracted from the selected element: level, color, linestyle, and
lineweight.
2 The user can select which of the properties from the source element
are to be changed in the Destination Elements.
3 The user can select any number of elements in MicroStation to be
modified based on the selected properties of the source element.
This sounds simple enough. Lets get started. Even though the form can
be imported from the CD, we will discuss the entire process of creating
the form.
The first thing we do is place the controls. As we work with an interface,
we will find ourselves resizing and moving the controls to make our
interface flow nicely for the user. Captions (when available) can be
modified immediately after we add each control.
Naming the controls is the next step. Here are the names of the controls
with which we will be interacting:
El frmMatchProperties
El btnSelectSource
El chkLevel
El txtLevel
El chkColor
El txtColor
El chkLinestyle
El txtLinestyle
El chkLineweight
El txtlineweight
El btnchange
El lblcount
El btnClose
El fraSource
El fraDestination
I Modeless Dialog Boxes I 355

As we develop this program, we should be thinking about the future of


this program. For example, the code in this form does not do anything
to the frames. We could leave their names as Framel and Frame2:
but we may decide to make the Destination frame invisible until the
Source Element is selected. Then, after the Source Element is selected,
we make the Destination Frame visible. We can do this using Frame2
as the frames name, but naming it fraDestinationin our code. This
tells us exactly what we are making visible or invisible without having to
browse through the frames on the form to find out which frame we are
affecting.

Control Properties
The Locked property of each TextBox should be True: We do not
want the user arbitrarily typing in values that do not work. The text
boxes will be populated by the source elements properties.
The Alignment property of each CheckBox should be
fmAlignmentLeW. This places the caption of the CheckBox on the
left of the CheckBox.
The ControlTipTextof the Select CommandButton is Click Here to
make the current selection the source element..
The ControlTipText of the Change Current Selection
CommandButton should be Click Here to modify the current
selection to match the selected properties from the Source element.:
The ControlTipText of the Close CommandButton should be
Click Here to Close the VBA Match Properties Program.
Later we will add code to display this form as modeless. This means the
user will be able to interact with Microstation even though the form is
displayed. This is important to keep in mind as we look at the code
behind the controls.

General DeclarationsArea
We have two lines of code in the general declarations area of our code.

O p t i o n Expl ic i t
D i m elemsource As Element
356 I Chapter 17: Interactive Modification I

Select Button
We can only use one element as the source element. When the user
clicks the Select button, the first thing we need to do is to discover how
many elements have been selected. If only one element has been
selected, we can continue. Otherwise, we will display one of two
MessageBoxes: one MessageBox if nothing was selected or a second if
more than one element was selected.
If only one element is selected, do the following:
1 Get the level (if a level is assigned to the element). The level name is
placed in the appropriate text box.
2 Get the color and display the number in the appropriate TextBox
and change the TextBox's Backcolor property to match the color of
the source element.
3 Get and place the linestyle property.
4 Get and place the lineweight property.
Now, let's look at the code behind the btnSelectSource-Click event:

P r i v a t e Sub b t n S e l e c t S o u r c e c C l i c k 0
D i m m y E l e m e n t s 0 As E l e m e n t
D i m myElemEnum As E l e m e n t E n u m e r a t o r
D i m myCol o r T a b l e As C o l o r T a b l e
S e t myElemEnum = ActiveModelReference.GetSelectedElements
myElements =
ActiveModelReference.GetSelectedElements.Bui1dArrayFromContents
If UBound(myE1ements) = 0 Then
Set elemsource = myElements(0)
If N o t m y E l e m e n t s ( O ) . L e v e l Is N o t h i n g Then
txtLevel .Text = m y E l e m e n t s ( 0 ) . L e v e l .Name
End If
Set myColorTable = ActiveDesignFile.ExtractColorTable
S e l e c t Case myEl e m e n t s ( 0 ) . C o l o r
Case - 1
txtColor.Text = "I'

txtColor.BackColor = RGB(255, 2 5 5 , 2 5 5 )
t x t L i nestyle.Text = -
myEl e m e n t s ( 0 ) . L i n e S t y l e . Name
txtLineweight .Text = myEl e m e n t s ( 0 ) . L i n e w e i g h t
Case E l s e
I Modeless Dialog Boxes I 357

txtColor.Text = myElements(0) .Color


txtColor.BackColor = -
myCol orTabl e.GetCo1 orAtIndex(myE1 ements(0) .Col or)
txtLinestyle.Text =
myElements(O).LineStyle.Name
txtLineweight.Text = myElements(O).LineWeight
End Select
Else
Select Case UBound(myE1ements)
Case -1
Ms g B ox "No " "Source " " element selected.", -
vbcritical, Me.Caption
Exit Sub
Case Else
MsgBox "Only one element can be the ""Source""" c%

"element. " , vbCri ti cal , Me. Capti on


Exit Sub
End Select
End If
End Sub
Plucing a We are working with the ElementEnumerator a little differently in this
Break Point instance. Instead of using "MoveNext" and getting the "Current"
in the code
ullows us to element, we get an array of elements using B u i 1 dArrayFromContents. If
step through the upper-bound of the array is 0, the array is composed of one element.
the code line This is what we want. If the upper-bound of the array is -1, this means
by line. This the array is empty and nothing was selected prior to clicking the button.
can help us
discover how
the program Change Current Selection Button
is working or When the user clicks the "Change Current Selection Button': we want to
to verifv that
it is working
change the selected properties of the selected elements to the source
as designed. element's properties. We also change the caption of the label to reflect
how many elements were modified. We create an array of elements from
the enumerator as we did in the previous example.

Private Sub btnchange-Click0


Dim m y E l e m e n t s 0 A s Element
Dim myElemEnum A s ElementEnumerator
Dim I As Long
Dim boo1 ElemModified A s Boolean
Dim lngModCount A s Long
1blCount.Caotion = "0 Element(s) modified."
358 I Chapter 17: Interactive Modification I
Show St a t u s 0 E 1 emen t ( s 1 mod i fi ed .
" "

Set myElemEnum = ActiveModelReference.GetSelectedElements


myElements = myEl emEnum. Bui 1 dArrayFromContents
lngModCount = 0
For I = LBound(myE1ements) T o UBound(myE1ements)
bool El emModi fi ed = Fa1 s e
If chkLevel.Value = True Then
myEl ements( I). Level = el emsource. Level
bool El emModi fi ed = True
End If
If chkColor.Value = True Then
myElements(I).Color = elemSource.Color
bool El emModi fi ed = True
End If
If chkLinestyle.Value = True Then
myEl ements( I). Li neStyl e = el emSource. Li neStyl e
bool El emModi fi ed = True
End If
If chkLineweight.Value = True Then
myElements(I).LineWeight = elemSource.LineWeight
bool El emModi fi ed = True
End If
If boolElemModified = True Then
myEl ements( I). Rewrite
lngModCount = lngModCount + 1
End If
Next I
1blCount.Caption = lngModCount & " Element(s) modified."
Showstatus 1 ngModCount & " El ement(s) modified."

End Sub
As we look at each element in the array, we only want to change the
properties based on the CheckBox values. We only increase the element
modified counter if a change was actually made. It is possible to select a
source element and multiple destination elements and have no changes
made if each of the CheckBoxes are set to false.

Close Button
The Close button unloads the Form.
I Providing User Feedback and Information I 359

Private Sub btnClose-Click0


Unload Me
End Sub

PROVIDING USER FEEDBACK


AND lNFORMATlON
Earlier in this chapter we learned how to provide the user feedback and
information through the use of the status bar area in Microstation. If we
look at the status bar area, we see that it changes as we move our cursor
over various tool bar buttons. Let's mimic this same functionality in
VBA by using the MouseMove events of several controls.

Private Sub UserForm-MouseMove(ByVa1 Button As Integer, -


ByVal Shift A s Integer, ByVal X A s Single,
ByVal Y A s Single)
ShowPrompt " "

End Sub

Private Sub f r a D e s t i n a t i o n - M o u s e M o v e ( B y V a 1 Button As Integer,


ByVal Shift As Integer, ByVal X As Single, -
ByVal Y A s Single)
ShowPrompt " "

End Sub

Private Sub f r a S o u r c e c M o u s e M o v e ( B y V a 1 Button As Integer, -


ByVal Shift As Integer, ByVal X As Single,
ByVal Y As Single)
ShowPrompt " "

End Sub
As the user moves the cursor around the form and the frames, we do not
want to display anything in the prompt because clicking on the form or
frame does not do anything. So, we use ShowPrompt with an empty
string so nothing displays.

Private Sub btnSelectSource-MouseMove(ByVa1 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 btnChangecMouseMove(ByVa1 Button As Integer, -


ByVal Shift As Integer, ByVal X As Single,
ByVal Y As Single)
360 I Chapter 17: Interactive Modification I
S how P r o m pt " Se 1e c t " " 0e s t in a t io n " " E 1 erne n t s : "
End Sub

P r i v a t e Sub b t n C l o s e c M o u s e M o v e ( B y V a 1 B u t t o n As I n t e g e r , -
B y V a l S h i f t As I n t e g e r , B y V a l X As S i n g l e ,
B y V a l Y As S i n g l e )
S h o w P r o m p t "C1 o s e " " V B A M a t c h P r o p e r t i e s " " "
End Sub

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.

P r i v a t e Sub U s e r F o r m - I n i t i a l i z e 0
ShowCommand " V B A M a t c h P r o p e r t i e s : "
End Sub

We use ShowCommand to set the Command area to "VBA Match


Properties" when the form is first initialized. This command continues
to display even though the prompt changes as the cursor is moved over
the other controls in our Form.

UserForm Queryclose
The Queryclose event is triggered just before the form 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).
vbFormControlMenu = 0
vbFormCode = 1
El vbAppWindows = 2
vbAppTaskManager = 3
For more information on what each of these values mean, look up
"Queryclose Constants" in the Microsoft VBA help.
I Providing User Feedback and Information I 361

In this program we are not concerned with how the form is closed, only
that it is closing.

Private Sub U s e r F o r m - Q u e r y C l o s e ( C a n c e 1 A s Integer


CloseMode A s Integer)
ShowPrompt " "

" "
Sh ow C omma n d
End Sub

Displaying the Form as Modeless


The code in the form is based entirely on the user's selection of elements
in Microstation. Although it is possible to select elements prior to
displaying the form, we actually need the user to make two distinct
selections: the source and the destination. The source selection can only
be one element. To allow the user to select elements in Microstation
while the form is displayed, we need to display the form as modeless.
Remember that modeless is the opposite of modal where, when the form
has focus, nothing else can be done in Microstation until the form is
closed. Modeless means that even while a form is displayed interaction
can continue inside Microstation. To display a form as modeless, we
must show it as such in a procedure in a code module.

Sub T e s t M a t c h P r o p e r t i e s ( 1
frmMatchProperties.Show vbModeless
End Sub
The procedure TestMatchProperties, 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 <FS>
key while holding down the <Alt> key (<Ah+ FS>).
362 I Chapter 17: Interactive Modification I
Here is the Match
Properties Form in use.
Notice the Command
and Prompt areas at the
bottom.
The Match Properties
Program is simple and
straightforward. We
allow the user to make
modifications to
elements in the Active
Model Reference by
selecting a source element and then using its properties to change the
selected destination elements while using a modeless dialog box.

f rmAl ignText.frm
The next form we will import into
our VBA project is the
frmA/ignText.frm file. This form
allows the user to perform text
alignment and distribution
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
displayed as modeless. This
b program involves geometric
calculations and moving text
elements based on those calculations.

Desired Functionality
Selected Text can be aligned Horizontally to the selected or
entered X value.
Text can be aligned Left, Center, or Right.
Text can be distributed evenly vertically so equal spacing exists
between each text element.
Only Text elements can be used, not Text Nodes.
I Providing User Feedback and Information I 363

Frames, command buttons, labels, and text boxes are used in this
project. Once again, you can import the form 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
El fraBasePoint
El fraHoriAlign
El btnPickBasePoint
El txtx
El txtY
El btnAlignLeft
El btnAlignCenter
El btnAlignRight
El btnDistributeVert

Pick Button
The code in the Pick buttons click event allows the user to select a
point in Microstation. The selected points X and Y components then
display in the text boxes.

Private Sub btnPickBasePoint-Click0


Dim myCIQ A s CadInputQueue
Dim myCIM A s CadInputMessage
Set myCIQ = CadInputQueue
Set myCIM = myCIQ.GetInput(msdCadInputTypeDataPoint, -
msdCadInputTypeReset)
Do
364 I Chapter 17: Interactive Modification I
S e l e c t Case rnyCIM.InputType
Case r n s d C a d I n p u t T y p e D a t a P o i n t
pt3BasePoint = rnyCIM.Point
txtX.Text = pt3BasePoint.X
txtY.Text = pt3BasePoint.Y
E x i t Do
Case rnsdCadInputTypeReset
E x i t Do
End S e l e c t
Loop
End Sub

We use the CadInputQueue to capture the selection of a point in


Microstation. When we initialize the CadInputMessage we specify that
we are only looking for datapoints and reset inputs. The Do ... Loop is
designed as an eternal loop. This means that without explicitly exiting,
the loop continues forever. We use the Do ... Loop code because we can
use an Exi t Do command that gets us out of the loop whenever we wish.

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.

P r i v a t e Sub t x t X L K e y P r e s s ( B y V a 1 K e y A s c i i A s M S F o r r n s . R e t u r n I n t e g e r )
S e l e c t Case KeyAsci i
Case A s c ( " 0 " ) To A s c ( " 9 " )
Case A s c ( " . " )
I f InStr(1, txtX.Text, "."I > 0 Then
KeyAscii = 0
End I f
Case E l s e
KeyAscii = 0
End S e l e c t
End Sub
I Providing User Feedback and Information I 365

P r i v a t e Sub t x t Y - K e y P r e s s ( B y V a 1 K e y A s c i i As M S F o r m s . R e t u r n 1 n t e g e r )
S e l e c t Case K e y A s c i i
Case A s c ( " 0 " ) To A s c ( " 9 " )
Case A s c ( " . " )
If InStr(1, txtY.Text, ".") > 0 Then
KeyAscii = 0
End I f
Case E l s e
KeyAscii = 0
End S e l e c t
End Sub

The Keypress event tells us the ASCII character code of the keyboard
character that was pressed. If we change the KeyAscii 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:
Is the Key Ascii between the numbers 0 to 9? If so, do nothing.
Always allow numbers 0 through 9 to be entered.
Is the Decimal key pressed? If so, look to see if a decimal is
already in the TextBox. If a decimal is already in the TextBox,
set KeyAscii to zero. Otherwise, do nothing and allow the
decimal to be entered.
Case Else (if any other key is pressed), set KeyAscii to zero as
though the key was not pressed in the first place.
It should be noted that this code only keeps numeric values from being
entered from the keyboard. It does not prohibit the user from pasting an
invalid entry into the TextBox from the Windows clipboard.

Align Left, Center, and Right


The best way to deal with these three alignment methods is one at a
time. We have three buttons. We could place code in each of the click
events of these buttons to perform the specific type of alignment
requested, but this would create a lot of redundant code. We will create a
function to take care of all horizontal alignments and provide for a
parameter to specify which alignment is to be performed.
366 I Chapter 17: Interactive Modification I
The Alignment Mode parameter could be defined as a string and we
could use LEFT, RIGHT, or CENTER as parameter values. This
works. There is a better way, though.
To get input from the Cad Input Queue, we can specify which types of
input we want by the using an enumeration, which is a list of constants
grouped together that usually refer to a specific method or property. We
will create our own enumeration to deal with alignments. In the General
Declarations area of this form, we declare this enumeration:

Enum A1 ignMode
msvbaAlignModeLeft = 1
msvbaAlignModeCenter = 2
msvbaAl ignModeRight = 3
End Enum

Now when we declare our procedure to align the selected text, it looks
like this:

Sub A1 ig n S e l e c t e d ( 0 p t i o n a l E l emAl ignMode As A1 ignMode = -


msvbaAl i g n M o d e L e f t )

We declare the parameter as optional so we can specify Left as the


default alignment. When we are using the Alignselected method in our
code, we see this:
Private Sub btnAlignCenter-Click ( )
Align Selected

Enumerations help us make sure that the parameter 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:

D i m p t 3 B a s e P o i n t As P o i n t 3 d

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 A1 ig n S e l e c t e d ( 0 p t i o n a l E l emAl ignMode As A1 ignMode =


msvbaAl i g n M o d e L e f t )
I Providing User Feedback and Information I 367

Dim myElemEnum As ElementEnumerator


Dim myElem As Element
Dim OriginPt As Point3d
Dim myTextElem As TextElement
Set myEl emEnum = Acti veModel Reference. GetSel ectedEl ements
Whi 1 e myEl emEnum.MoveNext
Set myElem = myElemEnum.Current
Select Case myElem.Type
Case msdElementTypeText
Set myTextElem = myElem
Select Case ElemAlignMode
Case msvbaAlignModeLeft
rnyTextElern.Move P o i n t 3 d F r o r n X Y ( p t 3 B a s e P o i n t . X ~ ~

myTextElem.Boundary.Low.X, 0)
myText El em. Rewrite
Case msvbaAlignModeRight
rnyTextElem.Move P o i n t 3 d F r o m X Y ( p t 3 B a s e P o i n t . X ~ ~

myTextElem.Boundary.High.X, 0)
myText El em. Rewrite
Case msvbaAlignModeCenter
myTextElem.Move P o i n t 3 d F r o m X Y ( p t 3 B a s e P o i n t . X - -
yTextE1em.Boundary.Low.X - -
(myTextE1em.Boundary.High.X - ~

myTextE1em.Boundary.Low.X) / 2 , 0)
myText El em. Rewrite
End Select
End Select
Wend
End Sub
When we begin executing this code, we know that in addition to
selecting text elements, the user may have selected other types of
elements. Since we only want to work with text elements, we use a
Sel ect Case statement to parse out the text elements from the others.
Next, we use another Se 1 ec t Case statement to move the text element
based on the type of alignment specified and the X value of the base
point. We rewrite the text element so the change made is permanent in
the file.

Left, Center, and Right Buttons


When the user clicks the left, center, or right buttons, the click event of
the respective button is triggered. Notice how we use our enumeration
values when calling AlignSelected.
368 I Chapter 17: Interactive Modification I

P r i v a t e Sub b t n A l i g n L e f t L C l i c k 0
A l i g n s e l e c t e d rnsvbaAlignModeLeft
End Sub

P r i v a t e Sub b t n A l i g n c e n t e r - C 1 i c k ( 1
A l i g n s e l e c t e d rnsvbaAlignModeCenter
End Sub

P r i v a t e Sub b t n A l i g n R i g h t - C l i c k 0
A l i g n s e l e c t e d rnsvbaAlignModeRight
End Sub

Degrees of Complexity
There are three degrees of complexity in this program. The degrees and
their tasks are as follows:
LOW: Pick a point, place X and Y components into TextBoxes.
Medium: Align selected Text Elements Left, Center, or Right.
High: Vertically Distribute selected Text Elements evenly.

We have already discussed the Low and Medium complexity tasks. It is


now time for the High complexity task. This task is not highly complex
because it is highly difficult. It simply requires more components for
everything to work correctly.

Vertically Distribute Selected Text Evenly


Here are four text elements in the file
chupterl7-AlignText.dgn. This file is on the
CD accompanying this book. The text
alignment code we have already discussed
takes care of the horizontal alignment. Now
we are faced with the task of making the text ,
look nice vertically. The spacing between
Note 1 and Note2 is tight, whereas the spacing between Note2 and
Note3 is loose (as it is between Note 3 and Note 4). We want the spacing
between each of these text elements to be the same. It is a simple task but
a number of considerations must be made before continuing.
I Providing User Feedback and Information I 369

1 After the user selects the text, we want even spacing between the top
and bottom elements without those elements moving.
2 On the screen it is readily apparent which element is on top and
which is on the bottom. But when we look at the selection in code,
we do not know which element is on top and which is on the
bottom.
3 On the screen we can see the proper order. But when we look at the
selection in code, we do not know the top-down order of the text
elements.
We will create distinct functions to accomplish each of the following
tasks:
Discover the minimum and maximum points of the selected
text elements.
Determine the vertical order in which the text elements appear.
Determine the number of selected text elements.
After we have these functions in place, we will be able to use them in
distributing the selected text elements.

Function GetMinMaxY(E1emType A s Long, ElementsIn As Variant) -


As Point3dO
Dim I As Long
Dim pt3StartPoint A s Point3d
Dim pt3EndPoint A s Point3d
Dim myTextElem A s TextElement
Dim boolPointsSet A s Boolean
bool PointsSet = False
F o r I = LBound(Elements1n) T o UBound(Elements1n)
Set myElem = ElementsIn(1)
Select Case myElem.Type
Case msdElementTypeText
Set myTextElem = myElem
If bool PointsSet = Fa1 se Then
pt3StartPoint = myTextElem.Boundary.High
pt3EndPoint = myTextElem.Boundary.High
boolPointsSet = True
End If
If myTextE1em.Boundary.High.Y > ~

pt3StartPoint.Y Then
I Chapter 17: Interactive Modification I
pt3StartPoint.Y = m y T e x t E 1 e m . B o u n d a r y . H i g h . Y
End If
If myTextE1em.Boundary.High.Y < pt3EndPoint.Y Then
pt3EndPoint.Y = m y T e x t E 1 e m . B o u n d a r y . H i g h . Y
End If
End Select
Next I
Dim pt3Points(0 T o 1) As Point3d
pt3Points(O) = pt3StartPoint
pt3Points(l) = pt3EndPoint
GetMinMaxY = pt3Points
End Function
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 SortElementsVertical ly(E1emType A s Long, -


ElementsIn A s Variant) As E l e m e n t 0
Dim I A s Long
Dim boolMadeChange As Boolean
Dim I n g E l e m I D O As DLong
Dim p t 3 B o u n d P t O As Point3d
Dim myTextEl em As TextEl ement
Dim myTextEl em2 As TextEl ement
Dim tmpID As DLong
Dim tmpPt As Point3d
ReDim lngElemID(0) As DLong
ReDim pt3BoundPt(O) As Point3d
For I = LBound(Elements1n) T o UBound(Elements1n)
Select Case El emType
Case msdElementTypeText
If ElementsIn(I).Type = msdElementTypeText Then
Set myTextElem = ElementsIn(1)
lngElemID(UBound(lngElem1D)) = myTextElem.ID
I Providing User Feedback and Information I 371

pt3BoundPt(UBound(pt3BoundPt)) =
myTextElem.Boundary.High
ReDim P r e s e r v e lngElemID(UBound(lngElem1D) + 1) As
DLong
ReDim P r e s e r v e pt3BoundPt(UBound(pt3BoundPt) + 1 ) As -
Point3d
End I f
End S e l e c t
Next I
ReDim P r e s e r v e lngElemID(UBound(lngElemID) - 1 ) As DLong
b o o l Madechange = True
Whi 1 e b o o l Madechange = True
b o o l Madechange = Fa1 s e
F o r I = L B o u n d ( l n g E l e m 1 D ) To U B o u n d ( l n g E l e m 1 D ) - 1
I f pt3BoundPt(I + 1).Y > p t 3 B o u n d P t ( I ) . Y Then
tmpID = lngElemID(1)
tmpPt = pt3BoundPt(I)
lngElemID(1) = lngElemID(1 + 1)
pt3BoundPt(I) = pt3BoundPt(I + 1)
l n g E l e m I D ( 1 + 1) = tmpID
p t 3 B o u n d P t ( I + 1) = tmpPt
boolMadeChange = True
End I f
Next I
Wend
D i m E l e m s I n O As Element
ReDim E l e m s I n ( 0 To U B o u n d ( l n g E l e m 1 D ) )
F o r I = L B o u n d ( l n g E l e m 1 D ) To U B o u n d ( l n g E l e m 1 D )
Set ElemsIn(1) = ActiveDesignFile.GetElementByID(lngElemID~1~~
Next I
SortElementsVertically = ElemsIn
End F u n c t i o n

There is a lot of code to look at here. After we divide it into four little
chunks, it becomes easier to understand.

Variable Declaration
D i m I As Long
D i m boolMadeChange As Boolean
D i m I n g E l e m I D O A s DLong
D i m p t 3 B o u n d P t O As P o i n t 3 d
D i m mrTextElem As TextElement
372 I Chapter 17: Interactive Modification I
Dim myTextEl em2 As TextEl ement
Dim tmpID As DLong
Dim tmpPt As Point3d
Two variables are declared as dynamic arrays (by using the empty
parenthesis). Dynamic arrays can change in size without losing their
values. Other variables are declared as well.

Dynamic Variable Array Population in


Preparation for Bubble Sort
ReDim lngElemID(0) As DLong
ReDim pt3BoundPt(O) As Point3d
For I = LBound(Elements1n) T o UBound(Elements1n)
Select Case El emType
Case msdElementTypeText
If ElementsIn(I).Type = msdElementTypeText Then
Set myTextElem = ElementsIn(1)
lngElemID(UBound(lngElem1D)) = myTextElem.ID
pt3BoundPt(UBound(pt3BoundPt)) = ~

myText El em. Boundary. High


ReDim Preserve -
lngElemID(UBound(lngElemID) + 1) A s DLong
ReDim Preserve -
pt3BoundPt(UBound(pt3BoundPt)+ 1) As ~

Poi nt3d
End If
End Select
Next I
ReDim Preserve lngElemID(UBound(lngElem1D) - 1) As DLong
ReDim Preserve pt3BoundPt(UBound(pt3BoundPt) - 1) As Point3d
We look at each element provided to us in the ElementsIn parameter to
see if it is of the correct type (in our example we are looking for text
elements). If it is, we get the text elements ID property and put it in one
of the dynamic array variables and get the elements Boundary.High
point and put it in the other dynamic array variable. We then re-declare
the dynamic array variables with the Preserve keyword so we dont lose
the previous values. After we have looked at each of the elements
selected, we re-declare the dynamic Array variables decreasing the size
of each by 1. Throughout the code above, we add one to the size of the
array after populating the upperbound variables so we need to take one
I Providing User Feedback and Information I 373

off after we have finished. Otherwise, we would have an array element


with nothing in it.

Bubble Sorting
bool Madechange = True
Whi 1 e bool Madechange = True
bool Madechange = Fa1 se
For I = LBound(lngElem1D) T o UBound(lngElem1D) - 1
If pt3BoundPt(I + 1).Y > pt3BoundPt(I).Y Then
tmpID = lngElemID(1)
tmpPt = pt3BoundPt(I)
lngElemID(1) = lngElemID(1 + 1)
pt3BoundPt(I) = pt3BoundPt(I + 1)
lngElemID(1 + 1) = tmpID
pt3BoundPt(I + 1) = tmpPt
boolMadeChange = True
End If
Next I
Wend
We have discussed bubble sorting previously. We are looking at the Y
values of two points. We want the highest Y values to be at the top of the
list. So, if a Y value lower down on the list is higher than the Y value just
above it in the list, we switch the two. When a switch is made we set the
variable boolMadeChangeto True. This means we will run through the
array again. We continue running through the array until a switch is not
made. When we find we have not made a switch, the sorting is complete.

Setting the Return Value


Dim E l e m s I n O A s Element
ReDim ElemsIn(0 T o UBound(lngElem1D))
For I = LBound(lngElem1D) T o UBound(lngElem1D)
Set ElemsIn(1) = ActiveDesignFile.GetElementByID(lngElemID~1~~
Next I
SortElementsVertically = ElemsIn
We are returning an array of elements for this function. When we did
our bubble sort, we swapped the point array values and also the ID array
values along with them to keep the IDS matched with their points. Now,
we use G e t E l ementByID to get the element back and put the element in
the return value array. We separated the IDS and points from the
374 I Chapter 17: Interactive Modification I
elements, so we did not need to hold onto large elements as we did our
sorting, only smaller points and ID types.
Determining the number of text elements is relatively easy compared
with the last function we just worked with. We get the element type we
want to count, the elements to be counted, and we return the number of
elements matching the type contained in the elements passed in.

Function GetSel ectedCount( E l emType As L o n g , ~

E l e m e n t s I n As V a r i a n t ) As L o n g
D i m I As Long
For I = L B o u n d ( E l e m e n t s 1 n ) To U B o u n d ( E l e m e n t s 1 n )
I f E l e m e n t s I n ( I ) . T y p e = ElemType Then
GetSelectedCount = GetSelectedCount + 1
End If
Next I
End F u n c t i o n

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 Distributiontask.

P r i v a t e Sub b t n D i s t r i b u t e V e r t L C l i c k 0
D i m M y P t s As V a r i a n t
D i m p t 3 S t a r t P o i n t As P o i n t 3 d
D i m p t 3 E n d P o i n t As P o i n t 3 d
D i m myElemEnum As E l e m e n t E n u m e r a t o r
D i m myElem As E l e m e n t
D i m m y E l e m s 0 As E l e m e n t
Dim I As Long
D i m m y T e x t E l em As T e x t E l e m e n t
D i m l n g S p a c e s As L o n g
D i m d b l S p a c e P e r E l e m e n t As D o u b l e
D i m s o r t E l e m s 0 As E l e m e n t
S e t myElemEnum = ActiveModelReference.GetSelectedElements
myElems = myEl emEnum. B u i 1 d A r r a y F r o m C o n t e n t s
MyPts = GetMinMaxY(msdElementTypeText, myElems)
1ngSpaces = GetSelectedCount(msdElementTypeText, m y E l e m s ) - 1
I f l n g S p a c e s > 1 Then
dblSpacePerElement = (MyPts(O1.Y - MyPts(l).Y) / 1ngSpaces
I Providing User Feedback and Information I 375

sortElerns = S o r t E l e r n e n t s V e r t i c a l l y ( r n s d E l e r n e n t T y p e T e x t , rnyElerns)
For I = L B o u n d ( s o r t E 1 e m s ) To U B o u n d ( s o r t E 1 e m s )
S e t myTextElem = sortElems(1)
myTextElem.Move Point3dFromXY(O, MyPts(O1.Y -
dblSpacePerElernent * I rnyTextE1ern.Boundary.High.Y)
~

m y T e x t E l em. R e w r i t e
myTextElem.Redraw
Next I
End I f
End Sub

A close look at the above code reveals the use of the three functions we
just finished discussing. G e t M i nMaxY, G e t S e l e c t e d c o u n t , and
S o r t E l e m e n t s V e r t i c a l l y are used. After we have sorted the elements
vertically, we move them so that they are spaced evenly.

Providing User Feedback and Information


Let's provide similar functionality to our previous program by supplying
the user feedback and information.

P r i v a t e Sub UserForm-MouseMove(ByVa1 B u t t o n A s I n t e g e r , -
B y V a l S h i f t A s I n t e g e r , B y V a l X As S i n g l e , B y V a l Y A s S i n g l e )
S h owS t a t u s " "
ShowPrompt " "

ShowCommand M e . C a p t i o n
End Sub

P r i v a t e Sub btnDistributeVert-MouseMove(ByVa1 B u t t o n A s I n t e g e r ,
B y V a l S h i f t As I n t e g e r , B y V a l X As S i n g l e , -
B y V a l Y As S i n g l e )
" "
S h owS t a t u s
ShowPrompt " D i s t r i b u t e T e x t V e r t i c a l l y "
ShowCommand M e . C a p t i o n
End Sub

P r i v a t e Sub f r a H o r i A l i g n - M o u s e M o v e ( B y V a 1 B u t t o n As I n t e g e r , -
B y V a l S h i f t A s I n t e g e r , B y V a l X As S i n g l e , B y V a l Y As S i n g l e )
S h owS t a t u s " "
ShowPrompt " "

ShowCommand M e . C a p t i o n
End Sub
I Chapter 17: Interactive Modification I
P r i v a t e S u b fraBasePointLMouseMove(ByVa1 B u t t o n A s I n t e g e r , -
B y V a l S h i f t As I n t e g e r , B y V a l X As S i n g l e , B y V a l Y As S i n g l e )
S how St a t u s " "
ShowPrompt " "

ShowCommand M e . C a p t i o n
End S u b

P r i v a t e S u b btnPickBasePoint-MouseMove(ByVa1 B u t t o n As I n t e g e r ,
B y V a l S h i f t As I n t e g e r , B y V a l X As S i n g l e , B y V a l Y As S i n g l e )
" "
S how St a t u s
ShowPrompt " S e l e c t Base P o i n t : "
ShowCommand M e . C a p t i o n
End S u b

P r i v a t e S u b b t n A l i g n R i g h t - M o u s e M o v e ( B y V a 1 B u t t o n As I n t e g e r ,
B y V a l S h i f t As I n t e g e r , B y V a l X A s S i n g l e , B y V a l Y As S i n g l e )
" "
S how St a t u s
ShowPrompt " A l i g n S e l e c t e d T e x t R i g h t as Base P o i n t "
ShowCommand M e . C a p t i o n
End S u b

P r i v a t e S u b btnAlignLeftLMouseMove(ByVa1 B u t t o n A s I n t e g e r , -
B y V a l S h i f t As I n t e g e r , B y V a l X As S i n g l e , B y V a l Y As S i n g l e )
S how St a t u s " "

ShowPrompt " A l i g n S e l e c t e d T e x t L e f t a t Base P o i n t "


ShowCommand M e . C a p t i o n
End S u b

P r i v a t e S u b btnAlignCenter-MouseMove(ByVa1 B u t t o n As I n t e g e r ,
B y V a l S h i f t As I n t e g e r , B y V a l X As S i n g l e , B y V a l Y As S i n g l e )
" "
S how St a t u s
S h o w P r o m p t "A1 i g n S e l e c t e d T e x t C e n t e r a t B a s e P o i n t "
ShowCommand M e . C a p t i o n
End S u b

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 top-
left 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.
I Providing User Feedback and Information I 377

f rmExportElements.f rm
The frmExportElemen ts.frm User
Form accomplishes a simple task:
it exports elements on specific
levels to a new design file.
The task for this project is simple.
The interface reflects this. We
need to allow the user to select
any number of levels, enter a file
name for the new file to be
created, and then click on the
Export button.

Control Names
1stLevels
txtFileName
btnExport
.
Control Properties
1stLevelsproperty MultiSelect is set to 2 -
fmMultiSelectExtended
1stLevelsproperty 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.

P r i v a t e Sub U s e r F o r m - I n i t i a l i z e 0
D i m m y L e v e l As L e v e l
D i m LevelNamesO As S t r i n g
D i m Madechange A s B o o l e a n
D i m tmpName A s S t r i n g
D i m I As L o n g
ReDim L e v e l N a m e s ( 0 )
F o r Each m y L e v e l I n A c t i v e D e s i g n F i l e . L e v e 1 s
L e v e l Names(UBound( L e v e l Names) ) = m y L e v e l .Name
I Chapter 17: Interactive Modification I
ReDim P r e s e r v e LevelNames(UBound(Leve1Names) + 1)
Next
ReDim P r e s e r v e LevelNames(UBound(Leve1Names) - 1)
Madechange = True
W h i l e Madechange = True
Madechange = False
F o r I = LBound(Leve1Names) To UBound(Leve1Names) - 1
I f S t r C o m p ( L e v e l N a m e s ( 1 ) . L e v e l N a m e s ( 1 + 1)) = 1 Then
tmpName = LevelNames(1)
LevelNames(1) = LevelNames(1 + 1)
LevelNames(1 + 1) = tmpName
Madechange = True
End I f
Next I
Wend
F o r I = LBound(Leve1Names) To UBound(Leve1Names)
1 s t L e v e l s . A d d I t e m L e v e l Names( I)
Next I
End Sub

When comparing numeric values, we can use greater than 0) 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 StrCornp
function to compare two strings.

P r i v a t e Sub b t n E x p o r t - C l i c k (
D i m m y F i l e N a m e As S t r i n g
D i m m y N e w F i l e As D e s i g n F i l e
D i m I As Long
D i m E l e m I D As DLong
D i m m y E l e m s 0 As E l e m e n t
D i m myElemEnum As E l e m e n t E n u m e r a t o r
D i m m y L e v e l As L e v e l
myFileName = txtFileName.Text
I f ActiveModelReference.1~30Then
C r e a t e D e s i g n F i 1 e " s e e d 3 d " . m y F i 1 eName, Fa1 s e
Else
C r e a t e D e s i g n F i 1 e " s e e d 2 d " , m y F i 1 eName, Fa1 s e
End I f
S e t myNewFile = OpenDesignFileForProgram(myFi1eName)
D i m m y S e l C r i t e r i a As New E l e m e n t s c a n c r i t e r i a
mySel Cri t e r i a . E x c l u d e A l 1 L e v e l s
I Providing User Feedback and Information I 379

For I = 1 To 1 s t L e v e l s . L i s t C o u n t
If lstLevels.Selected(1 - 1) T h e n
mySel Cri t e r i a . I n c l u d e L e v e l ~

ActiveModelReference.Levels(lstLeve1s.List (I - 1))
End I f
Next I
S e t myElemEnum = ActiveModel Reference.Scan(mySe1Criteria)
myElems = myElemEnum.BuildArrayFromContents
For I = LBound(myE1ems) To UBound(myE1ems)
myNewFile.Models(l).CopyElement myElems(1)
Next I
myNewFile.Save
MsgBox UBound(myE1ems) + 1 & " elements c r e a t e d i n f i l e " & vbCr & -
myFileName, v b I n f o r m a t i o n , Me.Caption
End Sub

We create a new design file using the CreateDesignFile method. We


then open that file using OpenDesignFileForProgram. This function
allows us to open and work with a file without the user seeing the file in
the Microstation interface.
Next, we create an Elementscancriteria object, so we only look for
elements on the selected levels. We ExcludeAllLevels and then begin
adding in the ones that are selected in the 1stLevels ListBox. As we
include the levels in our scan criteria, we could add them to the new
design file we just finished creating. This is not necessary as the levels
will be created when we copy elements to the new file. However, if we
select a level in our interface and it does not have any elements on it, the
new design file will not have that level.

Providing User Feedback and Information


The code imported with the form contains these events:

P r i v a t e Sub UserForm-MouseMove(ByVa1 B u t t o n As I n t e g e r , -
B y V a l S h i f t As I n t e g e r , B y V a l X As S i n g l e ,
B y V a l Y As S i n g l e )
ShowPrompt " "

" "
S h owS t a t u s
" "
S h ow C omma n d
End Sub

P r i v a t e Sub 1 s t L e v e l s - M o u s e M o v e ( B y V a 1 B u t t o n As I n t e g e r , -
B y V a l S h i f t A s I n t e g e r , B y V a l X As S i n g l e , B y V a l Y A s S i n g l e )
380 I Chapter 17: Interactive Modification I
ShowPrompt " "

S how St a t u s " "

" "
S h ow C o mm a n d
End Sub

P r i v a t e Sub t x t F i l e N a m e c M o u s e M o v e ( B y V a 1 B u t t o n A s I n t e g e r , -
B y V a l S h i f t As I n t e g e r , B y V a l X A s S i n g l e , B y V a l Y As S i n g l e )
ShowPrompt "I'

S how St a t u s " "

" "
S h ow C o mm a n d
End Sub

P r i v a t e Sub btnExport-MouseMove(ByVa1 B u t t o n A s I n t e g e r ,
B y V a l S h i f t As I n t e g e r , B y V a l X A s S i n g l e , B y V a l Y As S i n g l e )
ShowPrompt "I'

S how St a t u s " "

" "
S h ow C o mm a n d
End Sub

Nothing is being sent to the prompt, status, or command areas of the


status bar in Microstation. As we consider the functionality of this
program, what should these values be? We will let each individual
answer for themselves.
Here is the "VBA Files From Levels" form working. This program does
not need to be modeless because this program does not require user
interaction inside Microstation while the form is being displayed, but it
still needs to be shown from a procedure in a code module.
Sub T e s t F i 1 esFromLeve1 s ( )
frmExportElements.Show
End Sub
I Providing User Feedback and Information I 381

The above code is placed in a code


module so users can execute this
program.
Here is the interface in use. Any
number of levels can be selected
and exported to the file name
entered.

f rmDFAV.frm
The frmDFAKfrm program is used
to display attachments of design files.

The user selects a folder by clicking on the Browse button. When


selected, the selected folder is browsed for a Microstation .dgn file. Each
design file found is added to the File listbox. When the user clicks on a
382 I Chapter 17: Interactive Modification I
file in the File listbox, we look into the file for any attachments. All
attachments found are added to the Attachments listbox.

Control Names
txtFolder
btnBrowse
lstFiles
1stAttachments
We are going to add a few
elements in this program we
have not used thus far. We
could have the user type in a
folder. Let's have them select it Local Disk(C:)
Key Largo (0:)
instead. Here's the Folder projects on 'Puny' (V:)
PunylRem on 'Punyl' (Y:)
Selection dialog box we want: Store on 'Dev' (I:)
Shared Documents
How do we get it? We use the Administrator'sDocuments
Guest's Documents
Windows API. jerryw's Documents
jkw's Documents

The other thing we want to do


is store the settings of our
application so the next time
we use it we can recall those
settings. These settings are stored in the Windows registry.
Here is what this looks like:

VBA File Attachment Viewer


DeFaults i
.(DeFault)
........................ REG-SZ (value not set)
VBA File ReFerence Viewer Include Subs REG-SZ True
XM-AddInlW Path REG-SZ C:\Microstation VBA
Viewpoint

Program Components
Retrieve Settings from Registry on Form Initialize
Allow User to Select Root Folder
Search in Folder for .dgn files
I Providing User Feedback and Information I 383

Search in Folder's Sub Folders for .dgn files


When user clicks on file, display Attachments
When Program Closes, save settings to Registry

Retrieve Settings from Registry on Form


Initialize

P r i v a t e Sub U s e r F o r m - I n i t i a l i z e 0
txtFolder.Text = GetSetting("VBA F i l e Attachment Viewer",
"Defaults", "Path")
I f t x t F o l der .Text <> " " Then
chkSubFolders.Value = GetSetting("VBA F i l e Attachment
Viewer", -"Defaults", "Include Subs")
Popul a t e F i l e L i s t
End I f
End Sub

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.

Allow User to Select Root Folder


We use the Windows API to allow the user to select a folder. In the
general declarations area we declare the following:

P r i v a t e Type BrowseInfo
hWndOwner As Long
p i d l R o o t As Long
sDisplayName As S t r i n g
s T i t l e As S t r i n g
u l F l a g s As Long
l p f n As Long
l P a r a m As Long
i I m a g e As Long
End T y p e
P r i v a t e D e c l a r e F u n c t i o n SHBrowseForFolder L i b " s h e 1 1 3 2 . d l l " -

( b B r o w s e As B r o w s e I n f o ) As Long
P r i v a t e Declare Function SHGetPathFromIDList L i b " s h e 1 1 3 2 . d l l "
( B y V a l l I t e m A s L o n g , B y V a l s D i r As S t r i n g ) As L o n g
I Chapter 17: Interactive Modification I
P r i v a t e Const Bif-ReturnOnlyFSDirs = 1
P r i v a t e C o n s t Bif-DontGoBelowDomain = 2
P r i v a t e Const Bif-EditBox = 16
P r i v a t e Const Bif-NewDialogStyle = 64
P r i v a t e C o n s t Bif-UseNewui = 80
P r i v a t e Const Bif-BrowseForComputer = 4096
P r i v a t e Const Bif-BrowseForPrinter = 8192
P r i v a t e Const Bif-BrowseIncludeFiles = 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.

P r i v a t e Sub b t n B r o w s e c C 1 i c k ( 1
D i m MyBI A s B r o w s e I n f o
D i m F L i s t As L o n g
D i m D i r N a m e As S t r i n g
D i m S e l F o l d e r As L o n g
DirName = Space(255)
MyBI.sTitle = " S e l e c t Root F o l d e r : "
MyBI.sDisplayName = Space(255)
MyBI.ulFlags = Bif-ReturnOnlyFSDirs
FList = SHBrowseForFolder(MyB1)
Sel Folder = S H G e t P a t h F r o m I D L i s t ( F L i s t , DirName)
DirName = Left(DirName, I n S t r ( 1 , DirName, C h r ( 0 ) ) - 1)
I f DirName <> " " Then
txtFolder.Text = DirName
Else
t x t Fo 1 d e r .T e x t = " "

End I f
PopulateFileList
End Sub

PopulateFileList is a procedure that takes the folder in the TextBox and


begins looking for .dgn files.

Sub PopulateFileListO
1s t F i l e s . C l e a r
D i m m y F o l d e r As F o l d e r
D i m myFSO As New F i l e S y s t e m O b j e c t
I f txtFolder.Text <> "I' Then
S e t myFol d e r = myFSO.GetFo1 d e r ( t x t F o l d e r . T e x t )
FilesInFolder myfolder, "dgn", chkSubFolders, l s t F i l e s
I Providing User Feedback and Information I 385

End I f
1blFiles.Caption = "Design F i l e s i n Folder - " &
1 s t F i l e s . L i s t C o u n t & - " F i l e s Found."
End Sub

Popul a t e F i 1 e l i s t uses the FileSystemObject. This is a Windows


component we need to add to our references before we can use it.
In VBA, go to Tools > References to display the References dialog box:

When selected, the Microsoft Scripting Runtime provides an easy way to


find files and traverse folders and sub-folders.
The P opu 1 a t e F i 1 e L i s t method utilizes our F i 1 es I n Fo 1 d e r method.
The F i 1 e s I n Fol d e r method is a recursive method, which means it calls
itself. Here it is.

Sub Fi 1 esInFol der( F o l d e r I n As F o l d e r , F i l e E x t e n s i o n As S t r i n g ,


I n c l u d e s u b s As Boolean, -
L i s t T o P o p u l a t e As L i s t B o x )
D i m m y F i l e As F i l e
F o r Each m y F i l e I n F o l d e r I n . F i l e s
S e l e c t Case U C a s e ( R i g h t ( m y F i l e . N a m e , 3))
Case U C a s e ( F i 1 e E x t e n s i o n )
ListToPopulate.AddItem myFile.Path
End S e l e c t
Next
I f Includesubs = T r u e Then
D i m subFolder As F o l d e r
386 I Chapter 17: Interactive Modification I
For Each subFolder In FolderIn.SubFolders
FilesInFolder subfolder, FileExtension, -
Incl udeSubs, ListToPopul ate
Next
End If
End Sub
The first thing Fi 1 esInFolder does is looks for files in the "FolderIn"
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.
Foreachsub-folderwe findusing FilesInFolder,we call F i l e s I n F o l d e 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.

Private Sub 1stFiles-C1 ick( 1


1stAttachments.Clear
If 1stFiles.Text <> Then
"I'

Dim myDesFile As DesignFile


Set myDesFile = OpenDesignFileForProgram(lstFiles.Text, True)
Dim myAttachment As Attachment
For Each myAttachment In -
myDesFile.DefaultModelReference.Attachments
1stAttachments.AddItem myAttachment.AttachName
Next
myDesFile.Close
End If
1blAttachments.Caption = "Attachments in Selected File - & "

IstAttachments. ListCount & Attachments Found."


"

End Sub
I Interacting with MDL Applications I 387

Before looking at the attachments of a file, we need to open the file. We


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 OpenDesignFi 1 eForProgram to open
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.

P r i v a t e Sub UserForm-QueryClose(Cance1 As I n t e g e r , -
C l o s e M o d e As I n t e g e r )
S a v e s e t t i n g "VBA F i l e A t t a c h m e n t V i e w e r " , "Defaults", -

" Pa t h " , t x t F o 1 d e r . T e x t
S a v e s e t t i n g "VBA F i l e A t t a c h m e n t V i e w e r " , " D e f a u l t s " ,
" I n c l u d e Subs", - chkSubFolders.Va1ue
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 MDL APPLICATIONS


Let's record a macro where we import an image using the Microstation
menu File > Import > Image. Browse to C:\frogrurn
Files\Bentley\MicroStution\bentleyb.jpg and place it in Microstation.
After the image is placed, stop recording the macro.
Before we look at the macro that was created, we should discuss the two
methods of interacting with MDL Applications. The first method looks
like our previous use of the "SendCommand" method where, after the
command begins, we can supply points or other input as needed. The
second method, using dialog boxes, requires a class module that handles
the events of the dialog box.
The Import Image MDL application makes use of a dialog box so a new
class is created that is used with the recorded macro. Let's begin by
looking at the recorded macro. After we do, this we will look at the class
module created by the macro recorder.
388 I Chapter 17: Interactive Modification I
Sub Macro50
D i m s t a r t p o i n t As P o i n t 3 d
D i m p o i n t As P o i n t 3 d , p o i n t 2 As P o i n t 3 d
D i m l n g T e m p As L o n g

D i m m o d a l H a n d l e r As New M a c r o 5 M o d a l H a n d l e r
AddModal D i a l o g E v e n t s H a n d 1 e r m o d a l H a n d l e r

' The f o l l o w i n g s t a t e m e n t opens modal d i a l o g " S e l e c t Image F i l e "

' S t a r t a command
Cad1nputQueue.SendCommand "MDL LOAD PLAIMAGE"

' Coordinates are i n master u n i t s


startP0int.X = -6.270784
startP0int.Y = 23.160278
startP0int.Z = 011

' Send p o i n t s t o s i m u l a t e a d o w n - d r a g - u p a c t i o n
p0int.X = startP0int.X
p0int.Y = startP0int.Y
p0int.Z = startP0int.Z
point2.X = p 0 i n t . X + 2.938037
point2.Y = p0int.Y - 2.980928
point2.Z = p0int.Z
Cad1nputQueue.SendDragPoints p o i n t , p o i n t 2 , 1

RemoveModal D i a1 o g E v e n t s H a n d 1 e r m o d a l H a n d l e r
CommandState.StartDefaultCommand
End S u b

The class module created is named Macro5ModalHandler. After


declaring a few variables, the macro recorder declares a variable as a
"Macro5ModalHandler" and adds the events of this class. Next, the
"MDL LOAD PLAIMAGE" command is sent. This displays the dialog
box. After the dialog box is shown, the class module handles the entry of
the file path and name and closes the dialog box. When the dialog box
closes, we are back in the Macro5 procedure, which places the image in
the design file by 'dragging' points. The event handler is removed and
we finish out the procedure.
Let's take a look at the class module created.

Implements IModal DialogEvents


I Interacting with MDL Applications I 389

P r i v a t e Sub IModal DialogEvents-OnDialogClosed(ByVa1 -

DialogBoxNarne A s S t r i n g , ByVal D i a l o g R e s u l t A s M s d D i a l o g B o x R e s u l t )

End Sub

P r i v a t e Sub IModal DialogEvents-OnDialogOpened(ByVa1 -

DialogBoxName As S t r i n g , D i a l o g R e s u l t As M s d D i a l o g B o x R e s u l t )

I f DialogBoxName = " S e l e c t Image F i l e " T h e n

CadInputQueue.SendCommand -

" M D L COMMAND MGDS HOO K , f i1 e L is t-s e t F i 1 t e r Cmd * .c a 1 "

CadInputQueue.SendCommand -

"MDL COMMAND M G D S H O O K , f i l e L i s t - s e t D i r e c t o r y c m d " &


"C:\Program Files\Bentley\MicroStation\"

CadInputQueue.SendCommand
"MDL COMMAND MGDSHOOK,fileList-setFileNameCmd " &
" b e n t 1 e y b .j p g "

' Remove t h e f o l l o w i n g l i n e t o l e t t h e u s e r c l o s e t h e d i a l o g b o x .
D i a l ogResul t = m s d D i a l ogBoxResu1 t O K

End I f ' S e l e c t Image F i l e

End Sub

Every time the macro Ma c r 05 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
clsl magelnsertion. We have added two public variables that act as
properties to this class module.

Implements IModalDialogEvents
P u b l i c F i l e P a t h As S t r i n g
P u b l i c F i l e N a m e As S t r i n g

P r i v a t e Sub IModal DialogEvents-OnDialogClosed(ByVa1 -

D i a l o g B o x N a m e As S t r i n g , B y V a l D i a l o g R e s u l t As
MsdDi a1 o g B o x R e s u l t )
End Sub
390 I Chapter 17: Interactive Modification I

Private Sub IModalDialogEventspOnDialogOpened(ByVal


DialogBoxName As String, DialogResult As MsdDialogBoxResult)
If DialogBoxName = "Select Image File" Then
CadInputQueue.SendCommand -
"MDL COMMAND MGDSHOOK,fileList-setDirectoryCmd & - "

FilePath
CadInputQueue.SendCommand
"MDL COMMAND MGDSHOOK,fileListpsetFileNameCmd & "

Fi 1 eName
DialogResult = msdDialogBoxResultOK
End If
End Sub
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 TestImageInsertionO
Dim pointl As Point3d, point2 As Point3d
Dim modalHandler As New ClsImageInsertion
modalHandler. F i l e P a t h = "C:\Program Files\Bentley\MicroStation\"
modalHandler. FileName = "bentleyb. jpg"
AddModalDialogEventsHandler modalHandler
CadInputQueue.SendCommand "MDL LOAD PLAIMAGE"
point1.X = 0: point1.Y = 0: point1.Z = 0
point2.X = 1: point2.Y = 1: point2.Z = 0
CadInputQueue.SendDragPoints pointl, point2, 1
RemoveModalDialogEventsHandler modalHandler
CommandState.StartDefaultCommand
End Sub
Using FilePath and FileName properties for the class module allows the
class module to be used with any file path or name. Previously, the path
and name were hard-coded.

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 describe


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 users 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
IPrimitiveCommandEventsInterface.
User interaction with some dialogs in Microstation can be evaluated
through the use of the IModalDialogEvents.

In this Chapter:
Interface basics
Class module review
Class module lifecycle
The dynamics event

391
392 I Chapter 18: Interface Essentials I
The Locatecriteria object
IPrimitiveCommandEvents interface
Optimizing the dynamics event

INTERFACE
BASICS
The ability to capture user interaction in Microstation is powerful. To
harness this power, we create a new class module that implements the
interface. For example, to capture point selections in Microstation, we
insert a new class module in our VBA project and place the following
line in the General Declarations area of the class module:

Implements IPrimitiveCommandEvents
Using the Implements keyword in a class module means the class
module inherits the methods or events of the interface.

When we use the Implements keyword, the name of the interface


appears in the object combobox of the class module.

I m p l e m e n t s 1P r i m i t i v e c o

If we select the interface in the object combobox, as shown above, the


methods of the interface displays in the methods combobox.
As we can see, the IPrimitiveCommandEvents interface exposes six
methods or events. They are Cleanup, Datapoint, Dynamics, Keyin,
Reset, and Start.
Unlike user form controls, where we pick and choose which events we
want to display and work with, each and every method in an interface
must be declared, even if we are not going to do anything with them.
The easiest way to do this is to select each of the methods in the
I Class Module Review I 393

Methods combobox. Each time we do this, VBA automatically writes


the Sub ... End Sub code for us. If we follow this procedure for the
IPrimitiveCommandEvents interface, we see the following in the class
module:

Implements IPrimitiveCommandEvents

P r i v a t e Sub IPrimitiveCommandEvents-Cleanup0

End S u b

P r i v a t e S u b I P r i r n i t i v e C o m m a n d E v e n t s D a t a P o i n t ( P o i n t ( P 0 i n t As P o i n t 3 d ,
B y V a l V i e w As V i e w )

End S u b

P r i v a t e S u b I P r i m i t i v e C o m m a n d E v e n t s D y n a m i c s ( P o i n t As P o i n t 3 d , ~

B y V a l V i e w A s V i e w , B y V a l DrawMode As M s d D r a w i n g M o d e )

End S u b

P r i v a t e Sub IPrimitiveCommandEventsKeyin(ByVa1 K e y i n As S t r i n g )

End S u b

P r i v a t e Sub IPrimitiveCommandEvents-Reset0

End S u b

P r i v a t e Sub I P r i m i t i v e C o m m a n d E v e n t s S t a r t ( )

End S u b

Now we are ready to enter the code into the events.

CLASSMODULE
REVIEW
An interface must be exposed using a class module. We already
discussed class modules but a quick review is in order.
394 I Chapter 18: Interface Essentials I
We create a new class module by using the VBA menu Insert > Class
Module. By default, VBA names the new class modules Classl:
Class2: Class3,Class4,etc. We should rename them to something
that helps us understand what the class is. For example, we name a class
that writes to files clsFileWriter: In a later example, we will name a
Class LCE-Text to indicate we are working with the
ILocateCommandEvents interface (LCE) and that we are doing
something with text.
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
c1sNetNode: Here is the code:

P r i v a t e Type IPAddr
S e t 1 As B y t e
S e t 2 As B y t e
S e t 3 As B y t e
S e t 4 As B y t e
End T y p e

P u b l i c Name As S t r i n g
P r i v a t e I P A d d r e s s As I P A d d r

Sub P i n g 0
MsgBox P i n g i n g & 1PAddress.Setl & I. & -

IPAddress.Set.2 & I. & ~

IPAddress.Set3 & I. & ~

IPAddress.Set4, , Name
End Sub

Sub S e t I P A d d r e s s ( 1 P A As B y t e , I P B As B y t e , I P C As B y t e ,
I P D As B y t e )
IPAddress.Set1 = IPA
I Class Module Lifecycle I 395

IPAddress.Set2 = IPB
IPAddress.Set3 = IPC
IPAddress.Set4 = IPD
End S u b

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.

S u b T e s t C l sNetNodeA( 1
D i m myNetNode As c l s N e t N o d e
S e t myNetNode = New c l s N e t N o d e
m y N e t N o d e . S e t I P A d d r e s s 192, 1 6 8 , 1, 1
myNetNode.Name = Router
myNetNode. P i n g
End S u b

The second way to utilize a class module is to declare a variable as a


New class type and then begin setting variables and using methods as
shown below:

S u b T e s t C l sNetNodeB( 1
D i m myNetNode As New c l s N e t N o d e
m y N e t N o d e . S e t I P A d d r e s s 192, 1 6 8 , 1, 1
myNetNode.Name = Router
myNetNode. P i n g
End S u b

The difference between these two ways to declare and


initialize class modules is small. The net result is the
same however in this example.
ti

CLASSMODULE
LIFECYCLE
When we implement a simple class module, as we did with
clsNetNode: the class is alive only as long as the variable declared as the
396 I Chapter 18: Interface Essentials I
class module is in scope. In the two test procedures above, we declared
the variable myNetNode inside the procedures so the clsNetNode Class
is only alive inside the procedure where the variable was declared.
Variables declared in the General Declarations area as a class module are
available to all methods in the module in which it is declared and other
modules as well if the variable was declared as Public.
As soon as a variable declared as a specific class goes out of scope, the
object is automatically terminated. This is not the only way a declared
class can be terminated. You can terminate a class by setting the variable
representing the class to Nothing, as follows:

S e t myNetNode = Nothing

This explanation of the lifecycle of classes relates to most circumstances


where we utilize class modules. One exception to this rule is when we
use classes with the StartLocate and Startprimitive methods of the
Microstation Commandstate object. When we use StartLocate and
Startprimitive, Microstation holds onto the class and notifies it of events
until either Microstation is closed down, we use
CommandState.StartDefaultCommand, or we use one of the
Remove.... methods where applicable. We will see examples of the
Remove....methods later in this book.
It is important to understand the lifecycle of the classes we will be using
to implement Microstation interfaces because the code we use to call up
these classes will execute and the procedure will end but the class will
still be alive because Microstation is keeping it alive.
Lets discuss two Microstation interfaces. The first is the
ILocateCommandEvents interface.

ILocateCommandEvents
The ILocateCommandEvents Interface allows us to have the user select
or Locate an element. Here are the events exposed through the
ILocateCommandEvents interface:
Private Sub ILocateCommandEvents-Accept(ByVa1 Element As
Element, Point As Point3d, ByVal View As View)
Private Sub ILocateCommandEvents-Cleanup()
I Class Module Lifecycle I 397

Private Sub ILocateCommandEvents-Dynamics( Point As


Point3d, ByVal View As View, ByVal DrawMode As
MsdDrawingMode)
Private Sub ILocateCommandEvents-LocateFailedO
Private Sub ILocateCommandEvents-LocateFilter(ByVal
Element As Element, Point As Point3d, Accepted As Boolean)
Private Sub ILocateCommandEvents-LocateResetO
Private Sub ILocateCommandEvents-Start()
Each event is triggered at a specific time. Some of the events provide
information such as which element was located. Whenever we use
Microstations interface objects, each event or method must be declared,
whether we intend to use it or not. Lets take a look at an example.
We begin with capitalizing text elements.
The name of this class module is LCE-Text. Here is the code in the class
module:

Implements ILocateCommandEvents
P r i v a t e S e l E l e m e n t As E l e m e n t

P r i v a t e S u b ILocateCommandEvents-Accept(ByVa1 -
E l e m e n t As E l e m e n t , P o i n t As P o i n t 3 d , B y V a l V i e w As V i e w )
D i m e l e m T e x t As T e x t E l e m e n t
S e t e l emText = Element
elemText.Redraw msdDrawingModeErase
elemText.Text = UCase(elemText.Text)
e l e m T e x t . R e d r a w msdDrawingModeNorma1
e l emText. R e w r i t e
ActiveModel Reference.UnselectAl1 Elements
CommandState.StartDefaultCommand
End S u b

P r i v a t e Sub ILocateCommandEventsCleanupO

End S u b

P r i v a t e S u b I L o c a t e C o m m a n d E v e n t s - D y n a m i c s ( P o i n t As P o i n t 3 d , B y V a l
V i e w As V i e w , B y V a l DrawMode As M s d D r a w i n g M o d e )

End S u b
398 I Chapter 18: Interface Essentials I

P r i v a t e Sub ILocateCommandEvents-LocateFailedO
I f SelElement I s Nothing = F a l s e Then
ActiveModel Reference.Unse1 e c t A l 1 Elements
Set SelElement = Nothing
End I f
S h ow C o mm a n d " CA P T e x t "
ShowPrompt " S e l e c t T e x t t o b e C a p i t a l i z e d "
End Sub

P r i v a t e Sub I L o c a t e C o m m a n d E v e n t s L o c a t e F i l t e F i l t e r ( B y V a 1
~

E l e m e n t As E l e m e n t , P o i n t As P o i n t 3 d , A c c e p t e d As B o o l e a n )
Accepted = False
I f Element.IsTextElement = T r u e Then
S e t Sel Element = Element
Accepted = True
ActiveModel Reference.SelectElement Element, True
S h owC omma n d " CAP T e x t "
ShowPrompt " C l i c k a g a i n t o c o n f i r m . . ."
End I f
End Sub

ILocateCommandEvents-LocateResetO
P r i v a t e Sub
CommandState.StartDefaultCommand
End Sub

P r i v a t e Sub ILocateCommandEvents-Start0

End Sub

LocateFilter Event
The first event we work with is the LocateFilter event. This event gives
us the ability to specify whether the element selected meets our criteria.
By default, the accepted property is true. If the accepted property
remains true, the user is given the opportunity to "Accept" the selection
by clicking again in Microstation. When the user "Accepts" the
selection, the accept event is triggered and the code inside it is executed.
If in the LocateFilter event, the accepted parameter is set to false, the
LocateFailed event is triggered. It is common to re-start the interface
object if the LocateFilter event returns a false accepted value.
I Class Module Lifecycle I 399

Accept Event
Two conditions must exist before the accept event is triggered. First, the
LocateFilter event must exit with an accepted property of true. Second,
the user must Accept the already filtered element by left-clicking in
Microstation. A right-click in Microstation, after LocateFilter
successfully exits, resets the LocateFilter event but will not exit the
interface completely. When these two conditions (LocateFilter and User
Acceptance) are met, the code in the Accept event is executed.

LocateReset Event
The LocateReset event, the last triggered event in this interface, is
triggered when the user issues a reset by right-clicking in Microstation
before the LocateFilter Event has been entered or after the LocateFilter
event has been entered but the accepted property has been set to false.
Remember that the LocateReset event is telling us that the user has
requested a reset. It is up to our code to exit the interface by issuing a
CommandState.StartDefaultCommand.

LocateFailed Event
The LocateFailed event is triggered when the user clicks to select
something but nothing is located. This event could be used to exit out of
the interface by using CommandState.StartDefau1tCommand:

Start Event
The Start event, the first event triggered when utilizing this interface,
can be used to set up variables or other objects.

Cleanup Event
The Cleanup event is triggered just prior to the LocateReset event. As
the name implies, it can be used to clean up variables, objects, or
references used by the interface.

Dynamics Event
The Dynamics event provides dynamic real-time feedback. An example
later in this chapter demonstrates how it is used.
400 I Chapter 18: Interface Essentials I
Class Modules do not work by themselves - they need to be created by
other code. Here is the procedure that makes use of our new LCE-Text
class.

Sub t s t L C E - T e x t ( )
CommandState.StartLocate New LCELText
S h ow C omm a n d C A P Text
" "

ShowPrompt "Select Text to be Capital ized"


End Sub

Here are the


screen shots of
the program
working. Notice
the command
and prompts
guiding the user.

Here is another variation of the Capitalize Text program. The only


difference is the code handling the capitalizing of the text. It is now
placed in the LocateFilter event. This means the selected text element is
capitalized without waiting for user confirmation.

Implements ILocateCommandEvents
Private SelElement As Element

Private Sub ILocateCommandEvents-Accept(ByVa1 Element As Element,


Point A s Point3d, ByVal View As View)

End Sub
I Class Module Lifecycle I 401

P r i v a t e Sub ILocateCommandEvents-Cleanup()

End Sub

P r i v a t e Sub ILocateCommandEvents-Dynamics(Point As P o i n t 3 d . -
B y V a l V i e w As V i e w , B y V a l DrawMode As M s d D r a w i n g M o d e )

End Sub

P r i v a t e Sub ILocateCommandEvents-LocateFailedO
I f SelElement I s Nothing = F a l s e Then
ActiveModelReference.UnselectAllElements
Set SelElement = Nothing
End I f
S h ow C o mm a n d " CAP T e x t "
ShowPrompt " S e l e c t T e x t t o b e C a p i t a l i z e d "
End Sub

P r i v a t e Sub I L o c a t e C o m m a n d E v e n t s L o c a t e F i l t e F i l t e r ( B y V a 1 E l e m e n t As
E l e m e n t , P o i n t As P o i n t 3 d , A c c e p t e d As B o o l e a n )
Accepted = False
D i m e l e m T e x t As T e x t E l e m e n t
I f Element.IsTextElement = T r u e Then
S e t e l emText = Element
elemText.Redraw msdDrawingModeErase
elemText.Text = UCase(elemText.Text)
e l e m T e x t . R e d r a w msdDrawingModeNorma1
e l emText. R e w r i t e
ActiveModelReference.UnselectAllElements
CommandState.StartDefaultCommand
End I f
End Sub

P r i v a t e Sub I L o c a t e C o m m a n d E v e n t s L o c a t e R e s e t O
CommandState.StartDefaultCommand
End Sub

P r i v a t e Sub I L o c a t e C o m m a n d E v e n t s S t a r t ( )

End Sub
Here i s t h e code t h a t i n i t i a l i z e s t h e I n t e r f a c e O b j e c t .
402 I Chapter 18: Interface Essentials I

Sub tstLCE-Text20
CommandState.StartLocate New LCELTextP
S h ow C omm a n d C A P Text" "

ShowPrompt "Select Text to be Capital ized"


End Sub
We have not used the Dynamics event mentioned previously. Let's use it
now.
This code dynamically draws a new text element displaying the distance
between the original selection point and the cursor location. This is
done real-time. As the cursor moves, the text changes.

Here are two examples


of this Interface in
action. The first is while
the cursor is being
dragged after the initial
selection. The second is
after the mouse button
is clicked and the
"Distance Text" is placed. 3.087
,lt.iple contacts1

Lm o t i on

Here is the code for the Class Module named LCE-DistanceText.

Implements ILocateCommandEvents

Private selElem As Element


Private pt3StPoint As Point3d
Private dblDistance As Double

P r i v a t e Sub I L o c a t e C o m r n a n d E v e n t s A c c e p t ( B y V a 1 E l e m e n t As E l e m e n t ,
Point As Point3d, ByVal View A s View)
Dim txtElem As TextElement
Dim rotMatrix As Matrix3d
dblDistance = Point3dDistance(Point, pt3StPoint)
I Class Module Lifecycle I
Set txtElem = CreateTextElementl(selElem, R o u n d ( d b l D i s t a n c e , -
31, P o i n t , r o t M a t r i x )
ActiveModel Reference.AddElement t x t E l e m
t x t E l em. R e w r i t e
t x t E l em. Redraw
CommandState.StartLocate Me
End Sub

P r i v a t e Sub ILocateCommandEvents-Cleanup()

End Sub

P r i v a t e Sub I L o c a t e C o m m a n d E v e n t s D y n a m i c s ( P o i n t As P o i n t 3 d , ~

B y V a l V i e w As V i e w , B y V a l DrawMode As M s d D r a w i n g M o d e )
D i m t m p T x t E l e m As T e x t E l e m e n t
D i m r o t M a t r i x As M a t r i x 3 d
dblDistance = Point3dDistance(Point, pt3StPoint)
Set tmpTxtElem = CreateTextElementl(se1 Elem, Round(dblDistance, 3 ) , -

Point, rotMatrix)
t m p T x t E l e m . R e d r a w DrawMode
ShowPrompt " S e l e c t D i s t a n c e P o i n t : "
End Sub

P r i v a t e Sub I L o c a t e C o m m a n d E v e n t s L o c a t e F a i l e d O
CommandState.StartLocate Me
End Sub

P r i v a t e Sub ILocateCommandEvents-LocateFilter(ByVa1 -
E l e m e n t As E l e m e n t , P o i n t As P o i n t 3 d ,
A c c e p t e d As Boo1 e a n )
S e t s e l E l em = Element
pt3StPoint = Point
CommandState.StartDynamics
End Sub

P r i v a t e Sub I L o c a t e C o m m a n d E v e n t s L o c a t e R e s e t O
CommandState.StartDefaultCommand
End Sub

P r i v a t e Sub ILocateCommandEvents-Start0
S h ow C omma n d T e x t D is t a n c e
" "

ShowPromDt " S e l e c t E l e m e n t f o r B a s e P o i n t "


404 I Chapter 18: Interface Essentials I
End Sub
Here is the procedure that calls the interface through the class:

Sub t s t L C E - D i stanceText( )
CommandState.StartLocate New L C E L D i s t a n c e T e x t
End Sub

This macro demonstrates using a Dynamics event. A careful review of


the LocateFilter event shows the StartDynamics method. Without this
method, the Dynamics event would not be triggered. The Dynamics
event creates a new text element at the point of the cursor displaying the
distance between the original Locate Point and the cursor location.

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.

Implements ILocateCommandEvents
P r i v a t e S e l E l e m e n t As E l e m e n t
D i m myLC A s L o c a t e c r i t e r i a

Private Sub ILocateCommandEvents-Accept(ByVa1 Element As Element, -


P o i n t As P o i n t 3 d .
ByVal View As View)

End Sub

Private Sub ILocateCommandEventsLCleanupO

End Sub

Private Sub ILocateCommandEvents-Dynamics(Point As P o i n t 3 d , -


B y V a l V i e w As V i e w , B y V a l DrawMode A s M s d D r a w i n g M o d e )

End Sub

Private Sub ILocateCommandEventsLLocateFailedO


I f SelElement Is N o t h i n g = F a l s e Then
I Class Module Lifecycle I 405

ActiveModelReference.UnselectAllElements
Set SelElement = Nothing
End I f
S h ow C o mm a n d " CAP T e x t "
ShowPrompt " S e l e c t T e x t t o b e C a p i t a l i z e d "
End Sub

P r i v a t e Sub I L o c a t e C o m m a n d E v e n t s - L o c a t e F i l t e r ( B y V a 1 E l e m e n t As -
E l e m e n t , P o i n t As P o i n t 3 d , -
A c c e p t e d As B o o l e a n )
D i m e l e m T e x t As T e x t E l e m e n t
S e t e l emText = Element
elemText.Redraw msdDrawingModeErase
elemText.Text = UCase(elemText.Text)
e l e m T e x t . R e d r a w msdDrawingModeNorma1
e l emText. R e w r i t e
ActiveModel Reference.UnselectAl1 Elements
CommandState.StartDefaultCommand
End Sub

P r i v a t e Sub I L o c a t e C o m m a n d E v e n t s L o c a t e R e s e t O
CommandState.StartDefaultCommand
End Sub

P r i v a t e Sub I L o c a t e C o m m a n d E v e n t s - S t a r t 0
S e t myLC = CommandState.CreateLocateCriteria(True)
my LC. E x c l u d e A l 1 T y p e s
myLC.IncludeType (msdElementTypeText)
CommandState.SetLocateCriteria myLC
End Sub

We make use of the Locatecriteria object with S e t L o c a t e C r i t e r i a to


proactively filter the user's selection. This is preferable to allowing the
selection to be made, reviewing the element's properties, and accepting
or rejecting the selection inside the LocateFilter event. By using the
Locatecriteria object, we know the user has made a legitimate selection
by the time we get to the Locatecriteria event.
Here are the methods of the Locatecriteria object:
Sub ExcludeAllClasses()
Sub ExcludeAllLevels()
406 I Chapter 18: Interface Essentials I
El Sub ExcludeAllTypes()
El Sub ExcludeClass(ElemC1assAs MsdElementClass)
El Sub ExcludeLevel(Leve1As Level)
El Sub ExcludeType(TypeAs MsdElementType)
El Sub IncludeClass(ElemC1assAs MsdElementClass)
El Sub IncludeLevel(Level As Level)
El Sub IncludeOnlyHole()
El Sub IncludeOnlyLocked()
El Sub IncludeOnlyModified()
El Sub IncludeOnlyNew()
El Sub IncludeOnlyNonPlanar()
El Sub IncludeOnlyNonSnappable()
El Sub IncludeOnlyOld()
El Sub IncludeOnlyPlanar()
El Sub IncludeOnlySnappable()
El Sub IncludeOnlySolid()
El Sub IncludeOnlyUnlocked()
El Sub IncludeOnlyUnmodified()
El Sub IncludeType(Type As MsdElementType)
The Microstation VBA help file explains the use of each method shown
here as well as examples of how they are used.

IPrimitiveCommandEvents
We just finished discussing the ILocateCommandEvents interface. Its
primary use is selection (or location) of elements in a design file. Use the
IPrimitiveCommandEvents object to capture command entry and point
selection.
Here are the events we have to work with:
El Private Sub IPrimitiveCommandEvents-Cleanup()
I Class Module Lifecycle I 407

Private Sub IPrimitiveCommandEvents-DataPoint(Point As -


Point3d, ByVal View As View)
Private Sub IPrimitiveCommandEvents-Dynamics(Point As -
Point3d, ByVal View As View, ByVal DrawMode As
MsdDrawingMode)
Private Sub IPrimitiveCommandEvents-Keyin(ByVal Keyin As
String)
Private Sub IPrimitiveCommandEvents-Reset()
Private Sub IPrimitiveCommandEvents-Start()
Some of these should look familiar: Start, Reset, Cleanup, Dynamics. We
have already used these. Two events we have not worked with are
DataPoint and Keyin. Lets take a look at several examples of how these
events work.

PCE-Li n eTest
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 IPrimitiveCommandEvents
D i m p t 3 B a s e P o i n t As P o i n t 3 d
D i m b o o l S e t As B o o l e a n

P r i v a t e Sub I P r i m i t i v e C o m m a n d E v e n t s _ C l e a n u p O

End Sub

P r i v a t e Sub IPrimitiveCommandEvents-DataPoint(Point As P o i n t 3 d . -
ByVal View As View)
If boolSet = F a l s e Then
pt3BasePoint = Point
CommandState.StartDynamics
boolSet = True
Else
CommandState.StartDefau1tCommand
End I f
End Sub
408 I Chapter 18: Interface Essentials I
P r i v a t e Sub IPrimitiveCommandEvents-Dynamics(Point As P o i n t 3 d , -
B y V a l V i e w As V i e w , B y V a l DrawMode As M s d D r a w i n g M o d e )
D i m m y L i n e E l e m As L i n e E l e m e n t
S e t rnyLineElern = CreateLineElernentZ(Nothing. pt3BasePoint. P o i n t )
m y L i n e E l e m . Redraw DrawMode
End Sub

P r i v a t e Sub I P r i m i t i v e C o m m a n d E v e n t s K e y i n ( B y V a 1 K e y i n As S t r i n g )

End Sub

P r i v a t e Sub I P r i m i t i v e C o m m a n d E v e n t s R e s e t ( )

End Sub

P r i v a t e Sub IPrimitiveCommandEvents-Start0

End Sub

Most of the code in this example is in the DataPoint event and the
Dynamics event. Remember, we only want two points to be selected. We
use the variable boolSet so we know if the first point has been selected.
If the base point has not been selected, boolSet equals false and we take
the Point parameter and place it in the pt3BasePoint variable,
StartDynamics, and change boolSet to true.
As the cursor moves in Microstation the
Dynamics event is triggered. This \/
happens many times per second. We
need to make sure the code in the
Dynamics event is not too time-
consuming. In this example, we create a
new LineElement between the initial point selected and the current
cursor location given to us in the Point parameter.
Interface objects cannot run by themselves. They need code in a code
module or a form to call them up.

Sub P1 a c e l i n e ( )
CommandState.StartPrimitive New P C E - L i n e T e s t
End Sub
I Class Module Lifecycle I 409

Running this code demonstrates the fact that it works. The first point is
selected and the line is drawn as the cursor moves in Microstation. After
the second point is selected, we exit the object. Normally we would not
leave this object as it is. We would do something with the two points. We
may draw a line between the two points. Or we could write code to
divide the selected points into four equal segments and draw circles at
those division points. We will see this in a future example.

PCE-RecTest
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 PCE-RecTest.

Implements IPrimitiveCommandEvents
D i m p t 3 B a s e P o i n t As P o i n t 3 d
D i m b o o l S e t As B o o l e a n

P r i v a t e Sub I P r i m i t i v e C o m m a n d E v e n t s C l e a n u p O

End Sub

P r i v a t e Sub I P r i m i t i v e C o m m a n d E v e n t s - D a t a P o i n t ( P o i n t As P o i n t 3 d . -
ByVal View As View)
If boolSet = F a l s e Then
pt3BasePoint = Point
CommandState.StartDynamics
boolSet = True
Else
CommandState.StartDefau1tCommand
End I f
End Sub

P r i v a t e Sub I P r i m i t i v e C o m m a n d E v e n t s D y n a m i c s ( P o i n t As P o i n t 3 d , ~

B y V a l V i e w A s V i e w , B y V a l DrawMode A s M s d D r a w i n g M o d e )
D i m p t 3 R e c P o i n t s ( O To 3 ) A s P o i n t 3 d
D i m myShapeElem A s S h a p e E l e m e n t
pt3RecPoints(O) = pt3BasePoint
pt3RecPoints(l).X = P0int.X
pt3RecPoints(l).Y = pt3BasePoint.Y
410 I Chapter 18: Interface Essentials I
pt3RecPoints(2) = Point
pt3RecPoints(3).X = pt3BasePoint.X
p t 3 Rec Po in t s ( 3 .Y = P o i n t .Y
S e t myShapeElem = CreateShapeElementl(Nothing, p t 3 R e c P o i n t s )
m y S h a p e E l e m . R e d r a w DrawMode
End Sub

P r i v a t e Sub I P r i r n i t i v e C o r n r n a n d E v e n t s - K e y i n ( B y V a 1 K e y i n As S t r i n g )

End Sub

P r i v a t e Sub I P r i r n i t i v e C o r n r n a n d E v e n t s - R e s e t 0

End Sub

P r i v a t e Sub I P r i m i t i v e C o m m a n d E v e n t s S t a r t O

End Sub

Notice how the X and Y elements of each shape vertex is derived from
the base point and the current cursor point.

Sub P1 a c e R e c ( )
C o m m a n d S t a t e . S t a r t P r i r n i t i v e New PCE-RecTest
End Sub

The procedure PlaceRec initiates the


\/
PCE-RecTest class module.
After the first point is selected, a
rectangle is dragged from the first
point to the cursor. Since we are not
doing anything with the Reset event,
the only way to get out of this interface is to select the second point.

PCE-CircTest
The CircleTest class draws a circle with a center at the first selected point
to the cursor.

Implements IPrimitiveCommandEvents
D i m p t 3 B a s e P o i n t As P o i n t 3 d
D i m b o o l S e t As Boolean
I Class Module Lifecycle I 411

P r i v a t e Sub IPrimitiveCommandEvents-Cleanup0

End Sub

P r i v a t e Sub IPrimitiveCommandEvents-DataPoint(Point As P o i n t 3 d . -
B y V a l V i e w As V i e w )
If b o o l S e t = F a l s e Then
pt3BasePoint = Point
CommandState.StartDynamics
boolSet = True
Else
CommandState.StartDefaultCommand
End If
End Sub

P r i v a t e Sub IPrimitiveCommandEvents-Dynamics(Point As P o i n t 3 d . -
B y V a l V i e w As V i e w , B y V a l DrawMode A s MsdDrawingMode)
D i m myCi r c l e A s E l 1 i p s e E l e m e n t
D i m r o t M a t r i x As M a t r i x 3 d
D i m d b l Radius As Double
dblRadius = Point3dDistance(pt3BasePoint, Point)
S e t m y c i r c l e = CreateEllipseElementZ(Nothing, pt3BasePoint,
dbl Radius, dblRadius, r o t M a t r i x )
myCi r c l e . Redraw DrawMode
End Sub

P r i v a t e Sub IPrimitiveCommandEvents-Keyin(ByVa1 K e y i n As S t r i n g )

End Sub

P r i v a t e Sub I P r i m i t i v e C o m m a n d E v e n t s R e s e t O
CommandState.StartDefaultCommand
End Sub

P r i v a t e Sub I P r i m i t i v e C o m m a n d E v e n t s S t a r t O

End Sub

This example makes use of the Reset event. If the user resets the
command, we exit the interface object by calling S t a r t D e f a u l tCommand.

Sub P1 a c e C i r c ( 1
412 I Chapter 18: Interface Essentials I
C o m m a n d S t a t e . S t a r t P r i m i t i v e New P C E - C i r c T e s t
End Sub

PCE-Pol yTest
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. Lets begin with the class module:

Implements IPrimitiveCommandEvents
D i m p t 3 B a s e P o i n t As P o i n t 3 d
D i m b o o l S e t As Boolean
P u b l i c V e r t i c e s As L o n g

P r i v a t e Sub IPrimitiveCommandEvents-Cleanup0

End Sub

P r i v a t e Sub IPrirnitiveCommandEventsDataPoint(Point(P0int A s P o i n t 3 d ,
B y V a l V i e w As V i e w )
If boolSet