MicroStationV8iSs1VBAforAdvancedUsers TRN014750 1 0001

March 9, 2017 | Author: vthiyagain | Category: N/A
Share Embed Donate


Short Description

Download MicroStationV8iSs1VBAforAdvancedUsers TRN014750 1 0001...

Description

MicroStation VBA for Advanced  Users MicroStation V8i (SELECTseries 1) Bentley Institute Course Guide

TRN014750-1/0001

Trademarks AccuDraw, Bentley, the “B” Bentley logo, MDL, MicroStation and SmartLine are registered  trademarks; PopSet and Raster Manager are trademarks; Bentley SELECT is a service  mark of Bentley Systems, Incorporated or Bentley Software, Inc.  AutoCAD is a registered trademark of Autodesk, Inc.  All ther brands and product names are the trademarks of their respective owners. 

Patents United States Patent Nos. 5,8.15,415 and 5,784,068 and 6,199,125. 

Copyrights ©2000‐2009 Bentley Systems, Incorporated.  MicroStation ©1998 Bentley Systems, Incorporated.  All rights reserved. 

MicroStation VBA for Advanced Users

ii

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Table of Contents Course Overview  ____________________________________ 1 Course Description ____________________________________ 1 Target Audience_______________________________________ 1 Prerequisites _________________________________________ 1 Course Objectives _____________________________________ 2 Modules Included _____________________________________ 2

Building Commands  _________________________________ 3 Module Overview _____________________________________ 3 Module Prerequisites __________________________________ 3 Module Objectives_____________________________________ 4 Introductory Knowledge ________________________________ 4 Questions ________________________________________ 4 Answers__________________________________________ 4 Adding Elements – PrimitiveCommands ____________________ 4 Modifying Elements – LocateCommands ___________________ 7 Module Review _______________________________________ 9 Questions ________________________________________ 10

The User Interface ___________________________________ 11 Module Overview _____________________________________ 11 Module Prerequisites __________________________________ 11 Module Objectives_____________________________________ 11 Introductory Knowledge ________________________________ 11 Questions ________________________________________ 12 Answers__________________________________________ 12 Building a User Interface ________________________________ 12 Module Review _______________________________________ 15 Questions ________________________________________ 15

Working With Non‐Graphic Data  _______________________ 17 Module Overview _____________________________________ 17 Module Prerequisites __________________________________ 17 Module Objectives_____________________________________ 17 Introductory Knowledge ________________________________ 17

Dec-09

iii

Copyright © 2009 Bentley Systems, Incorporated

Table of Contents

Table of Contents

Questions ________________________________________ 18 Answers__________________________________________ 18 Storing Non‐Graphic Information With Elements_____________ 18 Tags ________________________________________________ 19 Databases ___________________________________________ 21 Connecting _______________________________________ 21 Elements with database records ______________________ 24 XML ________________________________________________ 27 UserData ____________________________________________ 27 Xdata _______________________________________________ 28 Module Review _______________________________________ 32 Questions ________________________________________ 32

Extending Functionality  ______________________________ 33 Module Overview _____________________________________ 33 Module Prerequisites __________________________________ 33 Module Objectives_____________________________________ 33 Introductory Knowledge ________________________________ 33 Questions ________________________________________ 33 Answers__________________________________________ 34 CExpression Processor__________________________________ 34 Calling C and MDL Functions _____________________________ 36 Using MDL functions in VBA classes ____________________ 38 Helpful notes______________________________________ 52 Module Review _______________________________________ 55 Questions ________________________________________ 55

Events  ____________________________________________ 57 Module Overview _____________________________________ 57 Module Prerequisites __________________________________ 57 Module Objectives_____________________________________ 57 Introductory Knowledge ________________________________ 58 Questions ________________________________________ 58 Answers__________________________________________ 58 Types of Events _______________________________________ 58 File events ________________________________________ 59 Interfaces ________________________________________ 59 Module Review _______________________________________ 62 Questions ________________________________________ 62

Standards Checker Extensions  _________________________ 63 Module Overview _____________________________________ 63 Module Prerequisites __________________________________ 63 Module Objectives_____________________________________ 63 Introductory Knowledge ________________________________ 63

Dec-09

iv

Copyright © 2009 Bentley Systems, Incorporated

Table of Contents

Table of Contents

Questions ________________________________________ 64 Answers__________________________________________ 64 Implementation _______________________________________ 64 Simple – use the basic framework _____________________ 65 Advanced – use the Fixes optional dialog________________ 66 Building Custom Standards Checker Applications ____________ 66 Questions ________________________________________ 76

Module Review Answers  _____________________________ 77 Building Commands____________________________________ 77 Questions ________________________________________ 77 Answers__________________________________________ 77 User Interface ________________________________________ 78 Questions ________________________________________ 78 Answers__________________________________________ 78 Working With Non‐Graphic Data _________________________ 79 Questions ________________________________________ 79 Answers__________________________________________ 79 Extending Functionality _________________________________ 79 Questions ________________________________________ 79 Answers__________________________________________ 80 Events ______________________________________________ 80 Questions ________________________________________ 80 Answers__________________________________________ 80 Standards Checker Extensions____________________________ 81 Questions ________________________________________ 81 Answers__________________________________________ 81

Appendix  __________________________________________ 83 New to MicroStation VBA? ______________________________ 83 The MicroStationDGN Object Model ___________________ 83 System Overview ______________________________________ 84 Configuration Variables for VBA _______________________ 84 Keyins for VBA_____________________________________ 85 COM Client Applications ________________________________ 86 ActiveX Controls and DLLs _______________________________ 87 Interface Programming _________________________________ 88 Sample Macros _______________________________________ 88 Scanning _________________________________________ 88 Geometry ________________________________________ 89 Working with other files _____________________________ 96 Dynamic user interface ______________________________ 97

Dec-09

v

Copyright © 2009 Bentley Systems, Incorporated

Table of Contents

Table of Contents

Table of Contents

vi

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Course Overview Course Description This course serves as an introduction to MicroStation VBA for application  developers with working knowledge of Visual Basic/VBA and as a follow‐on to the  MicroStation VBA Essentials course for those with prior experience with  MicroStation VBA. Regardless of a student’s background, this course provides an essential  foundation for the design, development, and deployment of MicroStation VBA  macros automating fundamental operations in MicroStation.

Target Audience The primary audience for this course is Application Developers — analysts and  programmers. This course may also be valuable for the following audience(s): •

Administrators



Consultants



Managers



Planners

Prerequisites

Dec-09



Have either a working knowledge of Visual Basic/VBA or successfully  completed the MicroStation VBA Essentials course. If the former, you should  review the section “New to MicroStation VBA?” in the Appendix to this course  guide before proceeding with this course.



Familiarity with basic MicroStation concepts such as design files, models,  references, and levels.

1 Copyright © 2009 Bentley Systems, Incorporated

Course Overview

Course Objectives



Familiarity with popular MicroStation tools and view controls.



Basic understanding of the MicroStation object model —in particular, the  Application, Attachment, DesignFile, Element, and ModelReference objects. 

Course Objectives After completing this course, you will be able to: •

Work with MicroStation's VBA objects to automate fundamental operations in  the product.



Deploy VBA macros in MicroStation.

Modules Included The following modules are included in this course: •

Building Commands



User Interface



Working With Non‐Graphic Data



Extending Functionality



Events



Standards Checker Extensions

Course Overview

2

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Building Commands Module Overview One of the basic building blocks of applications in MicroStation is the command  structure. VBA opens this up to application developers through interfaces. The  two interfaces used for commands are IPrimitiveCommandEvents and  ILocateCommandEvents. The command interfaces allow macros to follow a consistent structure. The  structure of the command is designed to work with the state machine format that  is built into MicroStation. By developing a collection of command classes, a set of  tools can be integrated in the workspace. The basic structure for the macro is to define a subroutine in a module that will  instantiate a class that implements one of the interfaces. The interface will  provide the entry points for MicroStation to call, that the class will use to react to  user actions. Interface programming is covered in depth in the module “Standards  Checker Extensions”.

Module Prerequisites •

Familiarity with the concepts of placing, locating, manipulating and modifying  elements in a model and the applicable tools.

Refer to the Course Overview for additional pre‐requisites.

Dec-09

3 Copyright © 2009 Bentley Systems, Incorporated

Building Commands

Module Objectives

Module Objectives After completing this module, you will be able to: •

Implement commands that add elements to a model.



Implement commands that interactively find and query or modify elements in  a model.

Introductory Knowledge Before you begin this module, let's define what you already know.

Questions 1

What does a VBA project file contain?

2

In a model scan what kind of object will return only elements that match  search criteria?

3

True or False: Hardly any MicroStation menu selections have a  corresponding key‐in you can use to directly invoke it.

Answers 1

Macros, including modules, classes, and forms which, in turn, contain  subroutines and functions.

2

ElementScanCriteria

3

False. Most MicroStation menu selections and tools have a corresponding  key‐in you can use to directly invoke it.

Adding Elements – PrimitiveCommands The IPrimitiveCommandEvents are typically used in commands that will be adding  elements to a model. Primitive commands will use the data point and reset actions to interact with the  user. The interface also defines entry points for the start of the command if key‐

Building Commands

4

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Adding Elements – PrimitiveCommands

ins are to be picked up and used, along with command termination through the  cleanup event. The following is the structure of a class that implements the  IPrimitiveCommandEvents interface. Option Explicit Implements IPrimitiveCommandEvents Private Sub IPrimitiveCommandEvents_Cleanup() End Sub Private Sub IPrimitiveCommandEvents_DataPoint(Point As Point3d, _ ByVal View As View) End Sub Private Sub IPrimitiveCommandEvents_Dynamics(Point As Point3d, _ ByVal View As View, ByVal DrawMode As MsdDrawingMode) End Sub Private Sub IPrimitiveCommandEvents_Keyin(ByVal Keyin As String) End Sub Private Sub IPrimitiveCommandEvents_Reset() End Sub Private Sub IPrimitiveCommandEvents_Start() End Sub

The IPrimitiveCommandEvents_Start method is called when this command  class is invoked. Typically this method will initialize any settings that the command  may need to set the initial prompts for the user.  The IPrimitiveCommandEvents_Keyin method is active if the usesKeyins  option is True when the command class is instantiated. This will allow the user to  type into MicroStation’s key‐in line while this command is active, for the class to  use.  The IPrimitiveCommandEvents_Reset method is called when the user presses  the Reset button. This is useful when a command wants to step backward.  The IPrimitiveCommandEvents_Cleanup method is called when the command  is terminated by another command being started.  The IPrimitiveCommandEvents_Dynamics method is active when the  CommandState.startDynamics is called. This method is used to let the command  show reaction to mouse movements.  The IPrimitiveCommandEvents_DataPoint method is called when the user  enters a data point. 

Dec-09

5

Copyright © 2009 Bentley Systems, Incorporated

Building Commands

Adding Elements – PrimitiveCommands

These methods combine to produce the standard workflow used by a command  that is adding an element to a model. In the next exercise a cell is to be built on the fly in the code. 

Exercise: Implement a command that will add a cell to a model 1

Launch MicroStation and open any design file.

2

Select Utilities > Macros > Project Manager.

3

Create and load the project Exercise_1.

4

Open the Visual Basic Editor.

5

Insert a class module and rename it Exercise1.

6

Type Implements IPrimitiveCommandEvents.

7

Type the function CreateSimpleGraphic that will be used to create a  simple graphic cell. Function CreateSimpleGraphic(oPoint As Point3d) As CellElement Dim oShape As ShapeElement Dim oElements(0) As Element Dim oCell As CellElement Dim ptsCorners(3) As Point3d

ptsCorners(1).X = 10 ptsCorners(2).X = 10 ptsCorners(2).Y = 10

Building Commands

6

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Modifying Elements – LocateCommands

ptsCorners(3).Y = 10

Set oShape = CreateShapeElement1(Nothing, ptsCorners, msdFillModeFilled) Set oElements(0) = oShape Set oCell = CreateCellElement1("Simple", oElements, Point3dZero, False)

Set CreateSimpleGraphic = oCell

End Function

8

Add the methods, including the processing logic, for the  IPrimitiveCommandEvents interface.

9

Add logic to the DataPoint method that calls CreateSimpleGraphic and  then displays and adds the cell to the model.

10 Switch to Module1, which is a normal module rather than a class module, 

and add a subroutine named PlaceCell that will serve as an entry point  for the macro. 11 In PlaceCell, create a new instance of the class Exercise1, using the 

line: CommandState.startPrimitive new Exercise1

12 Run the macro.

Press  in the VBA Editor and return to MicroStation. Note:  Often there is more than one way to create an element. Consider what 

information you will be gathering from users to create the element, then  decide on the method.

Modifying Elements – LocateCommands The ILocateCommandEvents are typically used to interactively find and query or  modify elements. Locate commands will use the “locate accept and process” algorithm for finding  elements. The interface defines entry points for validating the located element  and cleaning up after the command. Following is the structure of a class that  implements the ILocateCommandEvents interface.

Dec-09

7

Copyright © 2009 Bentley Systems, Incorporated

Building Commands

Modifying Elements – LocateCommands

Option Explicit Implements ILocateCommandEvents Private Sub ILocateCommandEvents_Accept(ByVal Element As Element, _ Point As Point3d, _ ByVal View As View) End Sub Private Sub ILocateCommandEvents_Cleanup() End Sub Private Sub ILocateCommandEvents_Dynamics(Point As Point3d, _ ByVal View As View, _ ByVal DrawMode As MsdDrawingMode) End Sub Private Sub ILocateCommandEvents_LocateFailed() End Sub Private Sub ILocateCommandEvents_LocateFilter(ByVal Element _ As Element, _ Point As Point3d, _ Accepted As Boolean) End Sub Private Sub ILocateCommandEvents_LocateReset() End Sub Private Sub ILocateCommandEvents_Start() End Sub

The CommandState.createLocateCriteria method can be used to create the  locate criteria object that will be used to filter, at a high level, the selectable  elements.  Once the LocateCriteria is created, use the include/exclude  methods to set the features of the object. Then the  CommandState.setLocateCriteria is called to put the filter in place.  In the ILocateCommandEvents_LocateFilter method, the macro has the ability  to preview the element. If it fails some test, then the element can be rejected.  If the user identifies an element that does not meet the requirements of the  locate criteria, the ILocateCommandEvents_LocateFailed method is called. In  this method, the macro can notify the user of the error condition.  ILocateCommandEvents_LocateReset is used when an element has been 

selected, but the user has pressed the Reset button.  In this case, many macros  can release some of the resources that have accumulated during the locate  process. 

Building Commands

8

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Module Review

The Cleanup method is called when the command is terminated by starting  another command.  This can be used to release resources that have been  consumed by this command.  The ILocateCommandEvents_Dynamics method can be activated by calling the  CommandState.startDynamics method. Dynamics can be used to show actions  like moving an element or other incremental changes that are a result of moving  the mouse or pointer.   The ILocateCommandEvents_Accept method is called when the user enters a  data point confirming the acceptance of the element(s) that have been selected. In the next exercise you will implement a command that lets the user identify an  element and then opens a dialog showing the type of element selected. 

Exercise: Implement a locate command 1

Continuing in the project Exercise_1, insert a new class module and  rename it Exercise2.

2

Type Implements ILocateCommandEvents.

3

Add the methods, including the processing logic, for the  ILocateCommandEvents.

4

Add logic to the Accept method that will get the type and set a MsgBox to  display this information.

5

Switch to Module1, and add a new subroutine named GetElementType  that will serve as the entry point for the module.

6

In GetElementType, create a new instance of the class Exercise2, using  the line: commandState.startLocate new Exercise2

7 

Run the macro.

Exercise: Implement a locate command with specified scan criteria 1

Add a LocateCriteria to the start method in Exercise2.

Module Review Now that you have completed this module, let’s measure what you have learned.

Dec-09

9

Copyright © 2009 Bentley Systems, Incorporated

Building Commands

Module Review

Questions

Building Commands

1

What are events?

2

What are the events that are available to the IPrimitiveCommandEvents  interface?

3

What are the events that are available to the ILocateCommandEvents  interface?

4

How does one make use of an interface?

10

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

The User Interface Module Overview Building dialogs can begin as a simple task, but adding advanced features to  enhance the user experience can take quite a bit of work. The UserForm set that is used in VBA is limited by design. To add features such as  resizing and menus, macros have to make use of the Win32 API.

Module Prerequisites •

Familiarity with the concept of locating elements in a model and the  applicable tools.



Familiarity with the native VBA tools available for building a UserForms.

Refer to the Course Overview for additional pre‐requisites.

Module Objectives After completing this module, you will be able to: •

Build dialog boxes with functionality more advanced than that available  through the native VBA UserForm controls.

Introductory Knowledge Before you begin this module, let's define what you already know.

Dec-09

11 Copyright © 2009 Bentley Systems, Incorporated

The User Interface

Building a User Interface

Questions 1

When creating a Message Box, how do specify its buttons be labeled “Yes”  and “No”?

2

Which does the ShowModal property of a UserForm determine?

3

How do you initiate the creation of a UserForm in a VBA project. {First multiple choice/fill in the blank answer.} {Second multiple choice/fill in the blank answer.} {Third multiple choice/fill in the blank answer.}

Answers 1

Specify vbYesNo as the second parameter of the call to the MsgBox  function.

2

The ShowModal property determines whether the form is modal.

3

In the Visual Basic Editor, select Insert > UserForm.

Building a User Interface When building a user interface, a developer must be mindful of how the user  thinks. If the user is a visual person, the user interface needs to use graphics to  convey a message. Some controls that may be useful are the SpinButton,  ScrollBar, and Image Control. The SpinButton and ScrollBar can be used for  manipulating the image that is displayed in the Image control. The Image Control  can be used to preview design graphics. To do this when working with  MicroStation elements, the dialog needs to use the GetPicture method from the  element class.  Dynamic contents allow the user interface to reflect the current set of  information. Building a macro that has a picture of each cell in an attached cell  library is an example of a macro that must create components on the fly. To do  this, the macro creates a collection of buttons to add to the dialog, and the dialog  must resize so they fit. TabPages are a method to make sense of large sets of related information. To start  with, TabPages are defined in a set of either TabStrip or MultiPage items. The  TabStrip displays the same set of controls on multiple pages, or tabs. The 

The User Interface

12

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Building a User Interface

MultiPage item displays a different set of controls on multiple pages. Tab pages  can be added to the UserForm at runtime.  The information may also be generated while the macro is running. To make  pages of the tab set visible, macros need to work with the tabpage.visible  property. To make a form resizable the macro needs to add the following  declarations. Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, _ ByVal lpWindowName As Any) As Long Private Declare Function GetWindowLong Lib "user32" Alias _ "GetWindowLongA" _ (ByVal HWND As Long, _ ByVal nIndex As Long) As Long Private Declare Function SetWindowLong Lib "user32" Alias _ "SetWindowLongA" _ (ByVal HWND As Long, _ ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long

Private Const WS_THICKFRAME = &H40000 Private Const GWL_STYLE = (-16)

Then when the form is activated the active method will need to call these  functions to change the style of the dialog that is used: Dim lngFrmHWND As Long Dim lngStyle As Long Dim lngRetVal As Long

lngFrmHWND = FindWindow("ThunderDFrame", Me.Caption) lngStyle = GetWindowLong(lngFrmHWND, GWL_STYLE) lngRetVal = SetWindowLong(lngFrmHWND, GWL_STYLE, _ lngStyle Or WS_THICKFRAME)

Finally, when the resize event occurs, the macro will need to take care of adjusting  the contents of the dialog to the new area.  An example follows. Private Sub UserForm_Resize()

ListBox2.Left = 1 ListBox2.Width = Me.Width - 9 ListBox2.Height = Me.Height / 2 - 5

Dec-09

13

Copyright © 2009 Bentley Systems, Incorporated

The User Interface

Building a User Interface

Label1.Top = ListBox2.Height + 2 Label1.Height = 5 Label1.Width = ListBox2.Width

ListBox1.Top = ListBox2.Height + Label1.Height + 5 ListBox1.Height = Me.Height / 2 - 10 ListBox1.Left = ListBox2.Left ListBox1.Width = ListBox2.Width Debug.Print "Height: " & Me.Height & " Width:" & Me.Width Debug.Print "the upper list box is "; ListBox2.Height; " at "; ListBox2.Top

tall starts _

Debug.Print "the lower list box is "; ListBox1.Height; " at "; ListBox1.Top

tall starts _

End Sub

In the following exercise you will build a dialog which can be used by a locate  macro to display the identified element. 

Exercise: Build the dialog 1

Continuing with the project Exercise_1 from “Building Commands”, insert  a userform and make it non‐modal.

2

Add an Image to the form.

3

Add a this method to the UserForm: Sub DisplayElement(oElement As Element) Dim stdPic As StdPicture With PreviewImageArea Set stdPic = oElement.GetPicture(PointsToPixelsX(.Width), _ PointsToPixelsY(.Height), True) .Picture = stdPic End With End Sub

The User Interface

14

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Module Review

4

In the ILocateCommandEvents_Accept method, call the  UserForm1.DisplayElement method.

5

Integrate the Image Area into the locate macro by calling the  Userform1.show method.

6

In the ILocateCommandEvents_Reset method, hide the form.

7

In the ILocateCommandEvents_Cleanup method, unload the form.

Module Review Now that you have completed this module, let’s measure what you have learned.

Questions

Dec-09

1

Name at least five standard user interface controls available to VBA  developers?

2

How can an Image Control be used in a dialog?

3

What methods must be included to make a form resizable?

15

Copyright © 2009 Bentley Systems, Incorporated

The User Interface

Module Review

The User Interface

16

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Working With Non‐Graphic  Data Module Overview Many applications require that a graphic element be supported by non‐graphic  information. MicroStation supports many options to accomplish this and there  are pros and cons for each solution. A developer must take these into account  when deciding how to store information.

Module Prerequisites •

Understanding of the concept of associating non‐graphic information with  graphic elements and the applicable tools.

Refer to the Course Overview for additional pre‐requisites.

Module Objectives After completing this module, you will be able to: •

Create VBA code to attach and extract tag data.



Create VBA code to create and maintain database linkages.



Create VBA code to set and get Xdata.

Introductory Knowledge Before you begin this module, let's define what you already know.

Dec-09

17 Copyright © 2009 Bentley Systems, Incorporated

Working With Non-Graphic Data

Storing Non-Graphic Information With Elements

Questions 1

What types of non‐graphic information can be associated with a graphic  element?

2

What is ODBC?

3

True or False: MicroStation provides a utility to convert data records from  an external database, which is linked to the active design file, into tag  data.

Answers 1

Tags Database linkages UserData Xdata XML

2

ODBC is a standard generic interface that allows applications to access SQL  compliant databases. MicroStation supports ODBC database linkages  among others.

3

True. The utility is the Database to Tag Convertor (DBTOTAG).

Storing Non‐Graphic Information With Elements Adding non‐graphic information allows for “smart” elements. And since graphics  do not always tell the whole story, you can store extra, non‐graphic, information  with elements. There are a number of methods for doing this, so the application  developer will have to choose the method that works best for their needs. •

If pre‐defined tools will be used or the information is relatively simple, tags  are a likely choice.



If the information needs to be shared outside of MicroStation, then a  database is the obvious choice.



If the information needs to be protected from editing, user data should be  used.



If the information needs to be shared with an AutoCAD application, Xdata is  the best choice.

Working With Non-Graphic Data

18

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Tags

Another option is XML, an emerging standard for information interchange that  will see more tools and development in MicroStation.

Tags Tags provide a method to link some fixed structure, non‐graphic, data to an  element. The tag process adds an element, which can be optionally displayed, to a  model. The information contained in a tag element can be edited with standard  MicroStation tools.  Elements must be added to a file before a tag can be added to an element. Tags  do not directly modify the element in the model. They keep a reference to the  base element so it can be found. The tag itself is defined by a TagSet.  

Exercise: Scanning a model for elements with tags. 1

In MicroStation, open the file Database.dgn in the folder  ...\WorkSpace\Projects\Examples\General\dgn. The model Tags contains tagged elements.

2

In the VBA Project Manager dialog, create and load the project Tags.

3

Switch to the Visual Basic Editor, insert a module, and create the following  macro: Sub TagReport() Dim oScP As ElementScanCriteria Dim oEnum As ElementEnumerator Dim oTagDefs As TagDefinitions Dim oTagSet

As TagDefinition

Dim oTag As TagElement Dim strFileName As String Dim tmpString As String Dim outString As String Dim oModel As ModelReference strFileName = ActiveDesignFile.FullName tmpString = Replace(strFileName, ".dgn", ".txt") Open tmpString For Output As 1 Set oScP = New ElementScanCriteria oScP.ExcludeNonGraphical

Dec-09

19

Copyright © 2009 Bentley Systems, Incorporated

Working With Non-Graphic Data

Tags

For Each oModel In ActiveDesignFile.Models outString = "*** Scanning model " & oModel.Name & " ***" Print #1, outString Set oEnum = oModel.Scan(oScP) Do While oEnum.MoveNext Dim oEl As Element If oEnum.Current.HasAnyTags Then Dim oTagsArray() As TagElement Dim i As Long Set oEl = oEnum.Current oTagsArray = oEl.GetTags For i = LBound(oTagsArray) To UBound(oTagsArray) If (i >= 1) Then If (oTagsArray(i - 1).TagSetName _ oTagsArray(i).TagSetName) Then outString = _ "Found Tag Set = " & _ oTagsArray(i).TagSetName Debug.Print outString Print #1, outString End If Else outString = "Found Tag Set = " & _ oTagsArray(i).TagSetName Print #1, outString End If outString = "--- " & _ oTagsArray(i).TagDefinitionName & _ " = " & oTagsArray(i).Value Print #1, outString Next Print #1, End If Loop Print #1, "--------------------------" Next Close 1 Debug.Print “TagReport processing is complete”

Working With Non-Graphic Data

20

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Databases

End Sub

4

Run the macro TagReport. The macro creates the text file Database.txt in the same folder as the  design file and writes to the text file the TagSetName and the tag data for  each element.

5 

Open Database.txt in a text editor such as Notepad to review the output.

Exercise: Tag an element 1

Add a tag to a selected element. There are good examples in the MicroStation VBA help document,  Objects, Tag Objects.

Databases Databases offer a flexible storage system for non‐graphic information. The  structure of the information must be determined by the database or application  designer. Applications need to maintain the validity of information, since the  database may not always be connected.  To work with database information, MicroStation has to connect to the data  source first, then work with the information that is stored on an element. The  information is kept external to MicroStation so it is available to other non‐ MicroStation users through other applications.

Connecting One of the connection types available to VBA developers is the ADO data  connection. The macro needs to create an ADOConnection, then set the  connection string. The connection string is the service provider type, the DSN  name, and, for some types of service providers — for example, Oracle — the user  name or id and the password.  Note:  The provider type is the software provider for the database driver, such as 

Oracle, OLEDB, or MSDASQL. To complete the next exercise, first make the GIS ODBC data source provided with  MicroStation available on the system you are using, as follows:

Dec-09

21

Copyright © 2009 Bentley Systems, Incorporated

Working With Non-Graphic Data

Databases



1

In the Windows Control Panel, select Administrative Tools > Data Sources  (ODBC).

2

In the ODBC Data Source Administrator dialog, select the User DSN tab (or,  if you have administrative rights you can use the System DSN tab) and click  Add.

3

In the Create New Data Source dialog, select the Microsoft Access Driver  (*.mdb) and click Finish.

4

In the ODBC Microsoft Access Setup dialog, type GIS as the data source  Name and, optionally, add a description of your choice.

5

Click Select.

6

Navigate to the ...\WorkSpace\System\macros directory and select  gis.mdb. You may need to copy and paste the full path to gis.mdb in the  Database File field.

7

Click OK.

8

In the ODBC Microsoft Access Setup dialog, click OK.

9

In the ODBC Data Source Administrator dialog, click OK.

Exercise: Connect to the GIS ODBC data source 1

In the VBA Project Manager dialog, create and load the project  ODBC_Datasource.

2

Switch to the Visual Basic Editor and insert a module that contains  declarations of variables needed to connect to the data source: 'Global variables for connecting to the database Public DNSname As String Public UIDPWD As String Public ADOconn As ADODB.Connection

3

Insert a UserForm, frmDBConnect, and add to it the following text field  and command button objects: txtDNSName — DSN Name cmdDBConnect — Connect cmdCancel — Cancel

4

Double‐click the Connect button object, and type the following code to  handle a click of the button: Private Sub cmdDBConnect_Click() On Error GoTo RDOCC_EH

Working With Non-Graphic Data

22

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Databases

'accept values from the user DNSname = txtDNSName.Value If DNSname "" Then UIDPWD = "Provider=MSDASQL;" UIDPWD = UIDPWD & "DSN=" UIDPWD = UIDPWD & DNSname Set ADOconn = New Connection ADOconn.ConnectionString = UIDPWD ADOconn.Open MsgBox ("Opened connection.") End If Unload Me Exit Sub

RDOCC_EH: MsgBox ("ERROR " & Err.Number & "

" & Err.Description)

End Sub

5

Type the following code to handle a click of the Cancel button: Private Sub cmdCancel_Click() End End Sub

6

Select Tools > References.

7

In the References dialog, select Microsoft ActiveX Data Objects 2.5 Library  and Microsoft ADO Ext. 2.8 for DDL and Security in addition to the libraries  already selected, then click OK.

8

Run the form.

9

In the DSN Name field, type GIS.

10 Click Connect. Note:  In the ...\WorkSpace\System\vba\examples folder, the VBA project files 

DataBaseExamples.mvba and dbcheck.mvba are for use with an Oracle  database. The userform for connecting to the data source is therefore  augmented to require a username and password.

Dec-09

23

Copyright © 2009 Bentley Systems, Incorporated

Working With Non-Graphic Data

Databases

Elements with database records When working with graphic elements that are connected to database records, the  process to extract the non‐graphic information is more complex. The element  only stores a pair of numeric ids. •

The Entity Number, which is related to a database table by looking in the  MSCATALOG table.



The MSLink which is the unique value stored in a column of the table.

The macro must first query the MSCATALOG table to get the tablename from the  Entity Number. Once the table name is known, the macro can then query that  table based on the MSLink number to get the information from the table. To work  with the data, the macro will build a RecordSet that will be used to hold the  results of the queries.  Some of the queries that you need will appear as follows. 'Get the Table name for a given entity. Public Function GetTableName(MSCATstr As String, EntNum As Integer) _ As String On Error Resume Next Dim RecordCount As Integer Dim RecSet1 As adodb.Recordset RecordCount = 1 'take this out for access since the USER_TABLES table does not exist! If dbtype = "Oracle" Then '

Set RecSet1 = GetRecordSet(ADOconn, "SELECT TABLE_NAME FROM



USER_TABLES WHERE TABLE_NAME = '" + MSCATstr + "'")

'

RecordCount = RecSet1.RecordCount

End If If RecordCount < 1 Then 'no entry found for given tablename MsgBox "MSCATALOG Not Found!" RecSet1.Close Set RecSet1 = Nothing GetTableName = "" ElseIf RecordCount = 1 Then RecordCount = 0 Dim RecSet2 As adodb.Recordset

Working With Non-Graphic Data

24

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Databases

Set RecSet2 = GetRecordSet(ADOconn, "SELECT TABLENAME FROM " + _ MSCATstr + " WHERE ENTITYNUM = " & CStr(EntNum)) RecordCount = RecSet2.RecordCount If RecordCount = 0 Then MsgBox "No Table for Entity: " & CStr(EntNum), vbOKOnly RecSet2.Close Set RecSet2 = Nothing GetTableName = "" ElseIf RecordCount = 1 Then GetTableName = RecSet2!TableName RecSet2.Close Set RecSet2 = Nothing Else MsgBox "Multiple Tables for Entity: " _ & CStr(EntNum), vbOKOnly RecSet2.Close Set RecSet2 = Nothing GetTableName = "" End If Else MsgBox "MSCATALOG is not Unique!" RecSet1.Close Set RecSet1 = Nothing GetTableName = "" End If End Function

Public Sub PrintLink(LinkIndex As Integer) 'prints database info for a given dblink Dim mslink As Integer Dim MSCATstr As String Dim EntNum As Integer Dim TableName As String Dim RS1 As adodb.Recordset Dim i As Integer If oElement.HasAnyDatabaseLinks Then

Dec-09

25

Copyright © 2009 Bentley Systems, Incorporated

Working With Non-Graphic Data

Databases

'check to see if element has database link mslink = dbLinks(LinkIndex).mslink EntNum = dbLinks(LinkIndex).EntityNumber MSCATstr = GetMSCATALOG TableName = GetTableName(MSCATstr, EntNum) If TableName "" Then Set RS1 = GetRecordSet(ADOconn, _ "SELECT * FROM " + TableName + " _ WHERE MSLINK = " & CStr(mslink)) Dim RecordCount As Integer RecordCount = RS1.RecordCount If RecordCount = 0 Then ' no records found with matching mslink number Debug.Print "No Records Found!!" ElseIf RecordCount = 1 Then ' one entry found for given mslink number For i = 0 To RS1.Fields.count - 1 Debug.Print

RS1.Fields.Item(i).Name

frmDBLinkInfo.ListBox1.List(i, 1) = "NULL" Next Else ' multiple entries found for mslink number Debug.Print "MSLINK is not Unique!!" End If RS1.Close Set RS1 = Nothing End If Else ' element does not have any database links Debug.Print "Element has no DB Links" End If End Sub



Exercise: Obtain database information 1

Create a macro to query an element and get the database information  that is related to the element.

Working With Non-Graphic Data

26

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

XML

XML XML is a technology for creating self‐documented structured storage of  information. XML can be used to create text files that can be interpreted by any  macro that is capable of parsing XML data. Note:  As of this writing, the XML API in VBA is limited to using the Microsoft MSXML6 

libraries. In the future, methods will be provided to add XML as additional  element information.

UserData UserData is extra information that is added to an element by a macro. The  structure of the information is determined by the macro.  The macro is assigned an ID number by Bentley. The ID number is used to prevent  macro conflict. To work with user data, the macro will need to first get the user  data as a block of information. Then it will need to process the block of data using  the CopyXXX method. The Copy methods use the copyToDataBlock parameter to  determine if the data is being copied to or from the datablock.  '

Do not use 22352 as your attribute ID.

You must obtain a

'

unique attribute ID from Bentley Systems.

Private Const attrId As Long = 22352 '

AddLinkage and GetLinkage both transfer the data using TransferBlock.

'

That way, it is easy to be certain that the transfer always occur in the

'

same order.

Private Sub TransferBlock(dblk As DataBlock, _ name As String, _ value As Long, _ copyToDataBlock As Boolean) dblk.CopyString name, copyToDataBlock dblk.CopyLong value, copyToDataBlock End Sub

Sub AddLinkage() Dim ele As Element

Dec-09

27

Copyright © 2009 Bentley Systems, Incorporated

Working With Non-Graphic Data

Xdata

Dim id As DLong Dim dblk As New DataBlock id = DLongFromLong(50296) Set ele = ActiveModelReference.GetElementByID(id) TransferBlock dblk, "Added by User Attributes Example", 50296, True ele.AddUserAttributeData attrId, dblk ele.Rewrite End Sub

Sub GetLinkage() Dim ele As Element Dim id As DLong Dim dblk() As DataBlock Dim value As Long, name As String id = DLongFromLong(50296) Set ele = ActiveModelReference.GetElementByID(id) dblk = ele.GetUserAttributeData(attrId) TransferBlock dblk(0), name, value, False MsgBox "NAME: " & name & ", VALUE: " & value End Sub

Note:  When macros use the CopyString method, VBA will copy a Unicode String to 

the element.  If the macro needs to be compatible with MDL the macro needs  to convert the String to an Array of bytes, then use the CopyByteArray  method.

Xdata Another method that applications can use to store information is Xdata. Xdata is a  format that AutoCAD uses to store extra information on elements. This has the  advantage of making the information compatible with the DWG format. Sub InterpretXData(Xdata() As XDatum) Dim I As Long Dim J As Long Dim D As DLong Dim Lev As Level

Working With Non-Graphic Data

28

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Xdata

Dim vt As Variant ' Using Debug.Print, display all of the XData to the Immediate Window of ' the Visual Basic Editor. For I = LBound(Xdata) To UBound(Xdata) With Xdata(I) Debug.Print GetXDatumName(.Type) & " --- "; If VarType(.Value) = vbEmpty Then Debug.Print "the value is empty" Else Select Case .Type Case msdXDatumTypePoint, _ msdXDatumTypeWorldDirection, _ msdXDatumTypeWorldSpaceDisplacement, _ msdXDatumTypeWorldSpacePosition ' Value is of the type Point3d. Debug.Print .Value.X; .Value.Y; .Value.Z Case msdXDatumTypeDatabaseHandle ' Value is a hex string. Get the element ' ID by calling DLongFromHexString Debug.Print "&H" & .Value Dim eleID As DLong eleID = DLongFromHexString(.Value) Case msdXDatumTypeBinaryData, _ msdXDatumTypeUnsupported ' Value is of the type Byte(). For J = LBound(.Value) To UBound(.Value) Debug.Print Hex(.Value(J)); " "; Next J Case Else ' Value is of a type that can be printed directly. Debug.Print .Value End Select End If End With ' Xdata(I) Next I End Sub

Dec-09

29

Copyright © 2009 Bentley Systems, Incorporated

Working With Non-Graphic Data

Xdata

Sub ShowEleXData() '

Find all of the XData in any element Dim ee As ElementEnumerator

Set ee = ActiveModelReference.GraphicalElementCache.Scan Do While ee.MoveNext If ee.Current.HasAnyXData Then Dim appNames() As String Dim index As Long

appNames = ee.Current.GetXDataApplicationNames

For index = LBound(appNames) To UBound(appNames) Dim aXdata() As XDatum

aXdata = ee.Current.GetXData(appNames(index)) InterpretXData aXdata Next End If Loop End Sub

Sub ShowAllModelXData() ' Find all XData contained on any model in the active design file Dim theModel As ModelReference Dim appNames() As String Dim index As Long For Each theModel In ActiveDesignFile.Models If theModel.HasAnyXData Then Debug.Print "-----Reporting XData for model " & _ theModel.Name & " -----" appNames = theModel.GetXDataApplicationNames For index = LBound(appNames) To UBound(appNames) Dim aXdata() As XDatum Debug.Print "----- Application " & _ appNames(index) & "-----" aXdata = theModel.GetXData(appNames(index))

Working With Non-Graphic Data

30

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Xdata

InterpretXData aXdata Next End If Next End Sub

Function GetXDatumName(xdType As MsdXDatumType) As String '

Translates an XData type into a String Select Case xdType Case msdXDatumTypeBinaryData GetXDatumName = "Binary Data"

Case msdXDatumTypeControlString GetXDatumName = "Control String"

Case msdXDatumTypeDatabaseHandle GetXDatumName = "Database Handle"

Case msdXDatumTypeDistance GetXDatumName = "Distance"

Case msdXDatumTypeInt16 GetXDatumName = "Int16"

Case msdXDatumTypeInt32 GetXDatumName = "Int32"

Case msdXDatumTypeLevel GetXDatumName = "Level"

Case msdXDatumTypePoint GetXDatumName = "Point"

Case msdXDatumTypeReal GetXDatumName = "Real"

Dec-09

31

Copyright © 2009 Bentley Systems, Incorporated

Working With Non-Graphic Data

Module Review

Case msdXDatumTypeScaleFactor GetXDatumName = "Scale Factor"

Case msdXDatumTypeString GetXDatumName = "String"

Case msdXDatumTypeUnsupported GetXDatumName = "Unsupported"

Case msdXDatumTypeWorldDirection GetXDatumName = "World Direction"

Case msdXDatumTypeWorldSpaceDisplacement GetXDatumName = "World Space Displacement"

Case msdXDatumTypeWorldSpacePosition GetXDatumName = "World Space Position"

End Select GetXDatumName = GetXDatumName & "(" & xdType & ")" End Function

Module Review Now that you have completed this module, let’s measure what you have learned.

Questions 1

What is the preferred method to work with an external database?

2

What is required to work with User Data?

3

What tools are used to work with XML data?

Working With Non-Graphic Data

32

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Extending Functionality Module Overview The “C” programming environment is available to applications in order to work  with the data structures used in MicroStation. Applications work through the Get/ SetCExpressionValue method of the Application Object to access the “C”  expression evaluator that is in MicroStation’s runtime environment.  

Module Prerequisites •

Familiarity with MDL as a platform for developing programmed  customizations for MicroStation.

Refer to the Course Overview for additional pre‐requisites.

Module Objectives After completing this module, you will be able to: •

Create VBA code utilizing MDL functions.

Introductory Knowledge Before you begin this module, let's define what you already know.

Questions 1

Dec-09

What are the components of an ADOConnection string?

33 Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

CExpression Processor

2

True or False: There are no practical limitations placed on the number of  MDL applications that can be simultaneously loaded.

3

What is the MDL dialog in MicroStation used for and how do you open it?

Answers 1

Service provider type, DSN name, user name or id, password

2

True

3

The MDL dialog is used to load and unload MDL applications and to view  technical details and key‐ins for MDL applications. To open it, select  Utilities > MDL.

CExpression Processor An expression is a valid programming statement as it would be put into a “C”  program. The GetCExpressionValue method takes in the “C” expression and,  optionally, the MDL application that is required.  The SetCExpressionValue  method takes in the expression used to set some value in an MDL application.  When an MDL function is not exposed to VBA, the Cexpression evaluator can  often be used to call the function.  The Cexpression processor can be used to call  MDL functions from external Visual Basic programs. retValue GetCexpressionValue(“mdlPolygon_pointInsideXY (“ & _ VarPtr(pCentroid) & “,” & _ VarPtr(boundryPoints(0)) & “,” & _ numboundryPoints & “,” _ tol & ")") Option Explicit

Implements IPrimitiveCommandEvents

Private Sub IPrimitiveCommandEvents_Cleanup() End Sub

Private Sub IPrimitiveCommandEvents_DataPoint(Point As Point3d, _ ByVal View As View) Dim volumeP As Double

Extending Functionality

34

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

CExpression Processor

Dim areaP As Double Dim closureP As Double Dim iXYP

As Double

Dim iXZP As Double Dim iYZP As Double Dim tol As Double Dim pCentroid As Point3d Dim pMoment As Point3d Dim pPrincipalMoments As Point3d Dim pPrincipalDirections As Point3d Dim retValue As Long

Dim oElement As Element tol = 1#

Set oElement = CommandState.LocateElement(Point, View, False) retValue = 0 If Not oElement Is Nothing Then If oElement.IsPlanarElement Or oElement.Type = _ msdElementTypeBsplineSurface Then retValue = _ GetCExpressionValue("mdlMeasure_surfaceProperties (" & _ VarPtr(areaP) & "," & _ VarPtr(pCentroid) & "," & _ VarPtr(pMoment) & "," & _ VarPtr(iXYP) & "," & _ VarPtr(iXZP) & "," & _ VarPtr(iYZP) & "," & _ VarPtr(pPrincipalMoments) & "," & _ VarPtr(pPrincipalDirections) & "," & _ oElement.MdlElementDescrP & "," & _ tol & "," & " 0)") Else retValue = GetCExpressionValue("mdlMeasure_volumeProperties (" & _ VarPtr(volumeP) & "," & _ VarPtr(areaP) & "," & _ VarPtr(closureP) & "," & _ VarPtr(pCentroid) & "," & _ VarPtr(pMoment) & "," & _ VarPtr(iXYP) & "," & _ VarPtr(iXZP) & "," & _

Dec-09

35

Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

Calling C and MDL Functions

VarPtr(iYZP) & "," & _ VarPtr(pPrincipalMoments) & "," & _ VarPtr(pPrincipalDirections) & "," & _ oElement.MdlElementDescrP & "," & _ tol & "," & " 0)") End If If retValue = 0 Then Debug.Print "the centroid is _ "; pCentroid.X; pCentroid.Y; pCentroid.Z Else Debug.Print "returned a "; retValue End If End If

End Sub

Private Sub IPrimitiveCommandEvents_Dynamics(Point As Point3d, _ ByVal View As View, ByVal DrawMode As MsdDrawingMode) End Sub

Private Sub IPrimitiveCommandEvents_Keyin(ByVal Keyin As String) End Sub

Private Sub Class_Initialize() End Sub

Private Sub IPrimitiveCommandEvents_Reset() End Sub

Private Sub IPrimitiveCommandEvents_Start() CommandState.SetLocateCursor End Sub

Calling C and MDL Functions One of the many features available to programmers in Visual Basic is the ability to  import functions from other libraries. This can be done using the Declare 

Extending Functionality

36

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Calling C and MDL Functions

statement and providing the prototype for the function call in a Visual Basic  module.  The syntax is as follows: [Public | Private] Declare Sub subName Lib "libName.dll" [Alias "AliasName"] [ ( [ argumentList] ) ]

[Public | Private] Declare Function FuncName Lib "libName.dll" [Alias "AliasName"] [ ( [ argumentList] ) ] As Type

Public|Private defines the scope of the procedure. All declarations in a class  module must be private. If neither Public or Private keyword is used, the  declaration is implicitly Public.

The subName or FuncName must start with a letter, be unique within the scope,  have less than 255 characters, and cannot be a VBA keyword, The library must be the complete name including the .dll extension unless it is one  of the standard Windows libraries. If the path is not specified then the search is  executed using the following logic: •

The directory that the application was loaded



The current working directory



The Windows\System32 directory



The Windows\System directory



The PATH environment variable

Optionally, the “Alias” can be used to define the name as written in the original  source code. That is the “subName” local to the VBA module, only the Alias is the  name in the DLL. The Argument list is the variable name and the type of information that the  library needs. Some common conversions are as follows.

Dec-09

C DataType

VBA DataType

BOOL

ByVal fValue as Integer

BYTE

ByVal bytValue as Byte

DWORD

ByVal ingValue as Long

int

ByVal intValue as Long

LPSTR

ByVal strValue as String

37

Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

Calling C and MDL Functions

Example declarations Public Declare Function WinHelp Lib "user32" Alias "WinHelpA" _ (ByVal hwnd As Long, _ ByVal lpHelpFile As String, _ ByVal lngCommand As Long, _ dwData As Any) As Long

Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex _ As Long) As Long

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, _ ByVal lpWindowName As Any) As Long Private Declare Function GetWindowLong Lib "user32" Alias _ "GetWindowLongA" (ByVal HWND As Long, _ ByVal nIndex As Long) As Long Private Declare Function SetWindowLong Lib "user32" Alias _ "SetWindowLongA" (ByVal HWND As Long, _ ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long

Private Const WS_THICKFRAME = &H40000 Private Const GWL_STYLE = (–16) Private Sub UserForm_Activate() Dim lngFrmHWND As Long Dim lngStyle As Long Dim lngRetVal As Long

lngFrmHWND = FindWindow("ThunderDFrame", Me.Caption) lngStyle = GetWindowLong(lngFrmHWND, GWL_STYLE) lngRetVal = SetWindowLong(lngFrmHWND, GWL_STYLE, _ lngStyle Or WS_THICKFRAME)

End Sub

Using MDL functions in VBA classes You can use MDL functions in VBA classes by importing libraries delivered with the  MicroStation SDK. 

Extending Functionality

38

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Calling C and MDL Functions



The stdmdlbltin.dll library provides access to the core mdl functions in  MicroStation.



The stdmdlaccessor.dll library provides some useful Element/Element  descriptor functions.

The MicroStation SDK is available for download at http://www.bentley.com/en‐US/Corporate/Bentley+Partner+Program/ Technology+Partners/MicroStation+SDK.htm. Some common MDL data types are: C DataType

VBA DataType

Dpoint3d

ByRef pt As Point3d

Transform

ByRef transP As Transform3d

DgnModelRefP

ByVal modelRef As Long

MSElementDescr ByRef edPP As Long

In Visual Basic, an Integer is 16 bits and a Long is 32 bits. Passing an argument by  reference generates a pointer to the variable. Some examples of using these are as follows.

Levels Option Explicit Private Declare Function mdlLevel_setActiveByName Lib "stdmdlbltin.dll" _ (ByVal parentLevelIdIn As Long, _ ByVal pLevelNameIn As Long) As Long

Sub SetActiveLevelFromLibraryTest() Dim ParentID As Long Dim oLevelName As String Dim status As Long Dim oPtr As Integer ' this needs to end up as 0xffffffff ParentID = &HFFFFFFFF oLevelName = "G-CODE" status = mdlLevel_setActiveByName(ParentID, StrPtr(oLevelName)) Debug.Print status End Sub

Dec-09

39

Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

Calling C and MDL Functions

Multi‐line placement Const NULLPtr As Long = 0

Declare Function mdlMline_create Lib "stdmdlbltin.dll" _ (ByVal mline As Long, _ ByVal seed As Long, _ ByRef normal As Point3d, _ ByRef points As Point3d, _ ByVal nPoints As Long) As Long

Declare Function mdlElmdscr_new Lib "stdmdlbltin.dll" _ (ByRef elDescrPP As Long, _ ByVal elemHeader As Long, _ ByVal element As Long) As Long

Function CreateMultiLine() As element Dim bytes(0 To 2000) As Byte Dim vertices(0 To 4) As Point3d Dim elmDescrP As Long

vertices(0) = Point3dFromXY(0,0) vertices(1) = Point3dFromXY(1,1) vertices(2) = Point3dFromXY(2,0) vertices(3) = Point3dFromXY(3,1) vertices(4) = Point3dFromXY(4,0)

mdlMline_create VarPtr(bytes(0)), NULLPtr, Point3dFromXYZ(0,0,1), _ vertices(0), 5 mdlElmdscr_new elmDescrP, NULLPtr, bytes(0)

Set CreateMultiLine = MdlCreateElementFromElementDescrP(elmDescrP)

End Function

Multi‐line information Declare Sub mdlMline_getInfo Lib "stdmdlbltin.dll" _ (ByRef nPoints As Long, _ ByRef nLines As Long, _ ByRef dist1 As Double, _ ByRef dist2 As Double, _

Extending Functionality

40

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Calling C and MDL Functions

ByRef zVector As Point3d, _ ByVal mline As Long) Declare Function ElmdscrAccessor_getMSElement Lib "stdmdlaccessor.dll" _ (ByVal ElementDescr As Long) As Long

Sub DumpMLineInfo() Dim ele As element Dim pElement As Long Dim elmDescr As Long Dim nPoints As Long Dim nLines As Long Dim dDist1 As Double Dim dDist2 As Double Dim zVector As Point3d Dim oScanCriteria As New ElementScanCriteria Dim ElementEnum As ElementEnumerator

oScanCriteria.ExcludeAllTypes oScanCriteria.IncludeType msdElementTypeMultiLine Set ElementEnum = ActiveModelReference.Scan(oScanCriteria)

Do While ElementEnum.MoveNext With ElementEnum.Current elmDescr = .MdlElementDescrP pElement = ElmdscrAccessor_getMSElement(elmDescr) mdlMline_getInfo nPoints, nLines, dDist1, dDist2, _ zVector, pElement Debug.Print "nPoints = " & nPoints; Debug.Print ", nLines = " & nLines; Debug.Print ", dDist1 = " & dDist1; Debug.Print ", dDist2 = " & dDist2 End With Loop End Sub

Note:  In MicroStation V8 XM Edition and later, there exists a PropertyHandler 

object in the VBA object model that provides read‐write access to the property  system used by the Element Information tool. Using PropertyHandler is 

Dec-09

41

Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

Calling C and MDL Functions

therefore a viable alternative not only for getting and setting element  properties but also design file, model, and attachment properties. Because  PropertyHandler works on a file's copy of an object, if a macro uses the  object to change element properties, those changes are not automatically  reflected in the Element object. The macro has to load the object again —  perhaps by using the GetElementByID method — to get the changes. There  are numerous examples of using PropertyHandler in the MicroStation VBA  help document, Objects, PropertyHandler Object.

References ' Reference File Parameters Const REFERENCE_DISPLAY = 1 Const REFERENCE_SNAP = 2 Const REFERENCE_LOCATE = 3 Const REFERENCE_SLOTACTIVE = 4 Const REFERENCE_SCALELINESTYLES = 5 Const REFERENCE_FILENOTFOUND = 6 Const REFERENCE_FILENAME = 7 Const REFERENCE_DESCRIPTION = 8 Const REFERENCE_LOGICAL = 9 Const REFERENCE_SCALE = 10 Const REFERENCE_ROTATION = 11 Const REFERENCE_ATTACHNAME = 13 Const REFERENCE_SCALE_MASTERUNITS = 15 Const REFERENCE_RESERVEDA = 16 Const REFERENCE_HIDDEN_LINE = 18 Const REFERENCE_DISPLAY_HIDDEN = 19 Const REFERENCE_CLIP_ROTATE = 20 Const REFERENCE_WCHAR_DESCRIPTION = 21 Const REFERENCE_WCHAR_LOGICAL = 22 Const REFERENCE_SCALE_STORED = 23 Const REFERENCE_SCALE_BY_UNITS = 24 Const REFERENCE_ANONYMOUS = 25 Const REFERENCE_OWNINGMODELREF = 26 Const REFERENCE_SOURCEMODELID = 27 Const REFERENCE_REFNUM = 28 Const REFERENCE_ELEMENTID = 29

Extending Functionality

42

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Calling C and MDL Functions

Const REFERENCE_DISPLAYRASTERREFS = 30 Const REFERENCE_WCHAR_MODELNAME = 31 Const REFERENCE_USE_LIGHTS = 32 Const REFERENCE_DONOTNEST = 33 Const REFERENCE_CLIPBACK = 34 Const REFERENCE_CLIPFRONT = 35 Const REFERENCE_NESTDEPTH = 36 Const REFERENCE_RENDERMODE = 37 Const REFERENCE_REDUNDANT = 38 Const REFERENCE_LEVEL_OVERRIDES = 39 Const REFERENCE_DISPLAYFILENAME = 40 Const REFERENCE_DISPLAYATTACHNAME = 41 Const REFERENCE_DISPLAYMODELNAME = 42 Const REFERENCE_DWGBLOCKNAME = 43 Const REFERENCE_DONTDETACHONALL = 44 Const REFERENCE_DISPLAYFLAG = 45 Const REFERENCE_MODELNOTFOUND = 46 Const REFERENCE_CLIP_ROTMATRIX = 47 Const REFERENCE_LEVEL = 48 Const REFERENCE_DWGUNITMODE = 49 Const REFERENCE_HSVVALUEADJUST = 50 Const REFERENCE_HSVSATURATIONADJUST = 51 Const REFERENCE_BASENESTDEPTH = 52 Const REFERENCE_RIGHTNOTGRANTED = 53 Const REFERENCE_PRINTCOLORADJUST = 54 Const REFERENCE_METADATAONLY = 55 Const REFERENCE_EXTENDED = 56 Const REFERENCE_HSVHUESETTING = 57 Const REFERENCE_HSVADJUSTMENTFLAGS = 58 Const REFERENCE_DISPLAYPRIORITY = 59 Const REFERENCE_NAMEDGROUP = 60 Const REFERENCE_REVISION = 61 Const REFERENCE_TRANSPARENCY = 62 Const REFERENCE_PLOT_3D = 63 Const REFERENCE_NESTOVERRIDES = 64 Const REFERENCE_NEWLEVELDISPLAY = 65

Dec-09

43

Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

Calling C and MDL Functions

Const REFERENCE_GLOBALLINESTYLESCALES = 66 Const REFERENCE_TREAT_AS_ELEMENT = 67 Const REFERENCE_PROVIDERID = 68 Const REFERENCE_RAWREVISION = 69 Const REFERENCE_REVISIONNOTFOUND = 70 Const REFERENCE_USEANNOTATIONSCALE = 71 Const REFERENCE_ATTACHMETHOD = 73 Const REFERENCE_ACTIVATESTATUS = 74 Const REFERENCE_SYNCHWITHSAVEDVIEW = 75 Const REFERENCE_USEVIEWFLAGS = 76 Const REFERENCE_SAVEDVIEWNAME = 77 Const REFERENCE_SAVEDVIEWELEMENTID = 78 Const REFERENCE_LEVELCONTROLSDISPLAY = 79 Const REFATTACH_NEST_NONE = 0 Const REFATTACH_NEST_COPY = 1 Const REFATTACH_NEST_DISPLAY = 2 Const REFCOLORTABLE_USEPREF = 0 Const REFCOLORTABLE_ALWAYS = 1 Const REFCOLORTABLE_NEVER = 2 Const REFERENCE_LOCATEON = 0 Const REFERENCE_LOCATEOFF = 1 Const REFERENCE_PARENTLOCATEOFF = 2 Const REFERENCE_NOLOCATERIGHTS = 3 Const REFERENCE_PARENTNOLOCATERIGHTS = 4 ' Reference File mdl Functions Declare Function mdlRefFile_attach Lib "stdmdlbltin.dll" _ (ByRef outModelRefP As Long, _ ByVal fileName As String, _ ByVal logical As Long, _ ByVal description As Long, _ ByRef masterOrigin As Point3d, _ ByRef referenceOrigin As Point3d, _ ByVal scale As Double, _ ByRef rotMatrix As Matrix3d, _ ByVal nClipPoints As Long, _ ByRef clipPoints As Point2d, _ ByVal levelDisplayFlag As Long, _ ByVal snapLock As Long, _ ByVal locateLock As Long) As Long

Extending Functionality

44

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Calling C and MDL Functions

Declare Function mdlRefFile_attachByView Lib "stdmdlbltin.dll" _ (ByRef outModelRefP As Long, _ ByVal fileName As String, _ ByVal logical As Long, _ ByVal description As Long, _ ByRef viewName As Long, _ ByVal scale As Double, _ ByRef centerPoint As Point3d, _ ByVal levelDisplayFlag As Long, _ ByVal snapLock As Long, _ ByVal locateLock As Long) As Long

Declare Function mdlRefFile_attachCoincident Lib "stdmdlbltin.dll" _ (ByRef outModelRefP As Long, _ ByVal fileName As String, _ ByVal logical As Long, _ ByVal description As Long, _ ByVal levelDisplayFlag As Long, _ ByVal snapLock As Long, _ ByVal locateLock As Long) As Long

Declare Function mdlRefFile_attachCoincidentExtended Lib _ "stdmdlbltin.dll" _ (ByRef outModelRefP As Long, _ ByVal fileName As String, _ ByVal logical As Long, _ ByVal description As Long, _ ByVal levelDisplayFlag As Long, _ ByVal snapLock As Long, _ ByVal locateLock As Long, _ ByVal callAsynchs As Long) As Long

Declare Function mdlRefFile_attachmentIdFromModelRef Lib _ "stdmdlbltin.dll" _ (ByVal modelRef As Long) As DLong

Declare Function mdlRefFile_beginAttachment Lib "stdmdlbltin.dll" _ (ByRef outModelRefP As Long, _ ByVal fileName As Long, _ ByVal modelName As Long, _ ByVal logical As Long, _ ByVal description As Long) As Long

Declare Function mdlRefFile_completeAttachment Lib "stdmdlbltin.dll" _ (ByVal modelRef As Long, _ ByVal nestFlag As Long, _

Dec-09

45

Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

Calling C and MDL Functions

ByVal nestDepth As Long, _ ByVal initialDisplay As Long) As Long

Declare Function mdlRefFile_detach Lib "stdmdlbltin.dll" _ (ByVal modelRef As Long) As Long

Declare Function mdlRefFile_getFromAttachmentID Lib "stdmdlbltin.dll" _ (ByRef refFilePP As Long, _ ByRef modelRefP As Long, _ ByVal srcModelRef As Long, _ ByVal attachmentID As DLong) As Long

Declare Function mdlRefFile_getInfo Lib "stdmdlbltin.dll" _ (ByVal modelRef As Long) As Long ' Returns a pointer to a structure

Declare Function mdlRefFile_getLocateLock Lib "stdmdlbltin.dll" _ (ByVal refP As Long) As Long

Declare Function mdlRefFile_getParameters Lib "stdmdlbltin.dll" _ (ByVal param As Long, _ ByVal paramName As Long, _ ByVal modelRef As Long) As Long

Declare Function mdlRefFile_getParent Lib "stdmdlbltin.dll" _ (ByVal refP As Long) As Long ' Returns a pointer to a structure

Declare Function mdlRefFile_getRefCount Lib "stdmdlbltin.dll" () As Long

Declare Function mdlRefFile_getSnapLock Lib "stdmdlbltin.dll" (ByVal refP As Long) As Long

Declare Function mdlRefFile_is3d Lib "stdmdlbltin.dll" (ByVal refP As Long) As Long

Declare Function mdlRefFile_isPrimary Lib "stdmdlbltin.dll" (ByVal refP As Long) As Long

Declare Function mdlRefFile_reattach Lib "stdmdlbltin.dll" _ (ByVal modelRef As Long, _ ByVal outName As String, _ ByVal fileName As String, _ ByVal ModelName As Integer) As Long

Extending Functionality

46

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Calling C and MDL Functions

Declare Function mdlRefFile_reload Lib "stdmdlbltin.dll" _ (ByVal modelRef As Long, _ ByVal updateDisplay As Long, _ ByVal forceReload As Long) As Long

Declare Function mdlRefFile_rotate Lib "stdmdlbltin.dll" _ (ByVal modelRef As Long, _ ByRef pivotP As Point3d, _ ByVal xrotation As Double, _ ByVal yrotation As Double, _ ByVal zrotation As Double, _ ByVal view As Long) As Long

Declare Function mdlRefFile_setClip Lib "stdmdlbltin.dll" _ (ByVal modelRef As Long, _ ByRef pts As Point2d, _ ByVal nverts As Long) As Long

Declare Function mdlRefFile_setParameters Lib "stdmdlbltin.dll" _ (ByVal param As Long, _ ByVal paramName As Long, _ ByVal modelRef As Long) As Long

Declare Function mdlRefFile_updateReference Lib "stdmdlbltin.dll" _ (ByVal modelRef As Long, _ ByVal displayMode As Long) As Long

Declare Function mdlRefFile_writeAttachment Lib "stdmdlbltin.dll" _ (ByVal modelRef As Long) As Long

Declare Function mdlRefFile_writeAttachmentConditionally Lib _ "stdmdlbltin.dll" _ (ByVal modelRef As Long) As Long

Declare Function mdlMline_create Lib "stdmdlbltin.dll" _ (ByVal mline As Long, _ ByVal seed As Long, _ ByRef normal As Point3d, _ ByRef points As Point3d, _ ByVal nPoints As Long) As Long

Dec-09

47

Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

Calling C and MDL Functions

Declare Function mdlElmdscr_new Lib "stdmdlbltin.dll" _ (ByRef elDescrPP As Long, ByVal elemHeader As Long, _ ByVal element As Long) As Long

Const NULLPtr As Long = 0

Sub DumpRefData() Dim activeModel As ModelReference Dim refModel As ModelReference Dim refModel2 As ModelReference Dim refModels As ModelReferences Dim attach As Attachment Dim attchmnts As Attachments Dim status As Long Dim refP As Long Dim modrefP As Long Dim pts(0 To 4) As Point2d Dim nverts As Long Dim refDesc As String Dim buffer(255) As Byte Dim dgnfile As DesignFile Dim param As Variant Dim scalefactor As Double

scalefactor = ActiveModelReference.UORsPerMasterUnit nverts = 5 pts(0).X = 0 pts(0).Y = 0 pts(1).X = 5 * scalefactor pts(1).Y = 0 pts(2).X = 5 * scalefactor pts(2).Y = 2 * scalefactor pts(3).X = 0 pts(3).Y = 2 * scalefactor pts(4).X = 0 pts(4).Y = 0

Extending Functionality

48

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Calling C and MDL Functions

Dim ModelName As String Dim LogicalName As String Dim Description As String

ModelName = "Default" LogicalName = "testing" Description = "test file"

status = mdlRefFile_beginAttachment(modrefP, ActiveDesignFile.Name, _ 0, StrPtr(LogicalName), StrPtr(Description))

If status = 0 Then status = mdlRefFile_setClip(modrefP, pts(0), nverts) Debug.Print "Reference Clip Status = " & status status = mdlRefFile_completeAttachment(modrefP, 2, -1, 0) End If End Sub

Declare Sub mdlElmdscr_setVisible Lib "stdmdlbltin.dll" _ (ByVal edP As Long, _ ByVal visible As Long)

Sub SetVisible() Dim ele As element Dim eleDescr As Long Dim oScanCriteria As New ElementScanCriteria Dim ElementEnum As ElementEnumerator Set ElementEnum = ActiveModelReference.Scan(oScanCriteria)

Do While ElementEnum.MoveNext Set ele = ElementEnum.Current

eleDescr = ele.MdlElementDescrP mdlElmdscr_setVisible eleDescr, 0 If ele.FilePosition 0 Then ele.Rewrite End If

Dec-09

49

Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

Calling C and MDL Functions

'now make it visible again ActiveDesignFile.Views(1).Redraw mdlElmdscr_setVisible eleDescr, 1 If ele.FilePosition 0 Then ele.Rewrite End If ActiveDesignFile.Views(1).Redraw Loop

End Sub

Element descriptors Declare Function mdlACS_getCurrent Lib "stdmdlbltin.dll" _ (ByRef originP As Point3d, _ ByRef rotMatrixP As Matrix3d, _ ByVal typeP As Long, _ ByVal nameP As Long, _ ByVal descriptionP As Long) As Long

Sub DoACS() Dim ele As LineElement Dim pntOrigin As Point3d Dim pntStart As Point3d, pntEnd As Point3d Dim rot As Matrix3d Dim iType As Integer Dim result As Long Dim tms As Transform3d

result = mdlACS_getCurrent(pntOrigin, rot, iType, 0, 0) rot = Matrix3dFromMatrix3dTimesMatrix3d(rot, _ Matrix3dFromScale(ActiveModelReference.UORsPerMasterUnit)) rot = Matrix3dInverse(rot)

tms = Transform3dFromMatrix3dPoint3d(rot, pntOrigin)

' Create an element using this transform pntStart = Point3dFromTransform3dTimesPoint3d(tms, Point3dFromXY(0,0)) pntEnd = Point3dFromTransform3dTimesPoint3d(tms, Point3dFromXY(3,3))

Extending Functionality

50

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Calling C and MDL Functions

Set ele = CreateLineElement2(Nothing, pntStart, pntEnd) ele.Redraw ActiveModelReference.AddElement ele

End Sub

The method MdlCreateElementFromElementDescr will appear when you enable  the Show hidden members option in the Object Browser. Other methods available are: •

MdlGetModelReferenceFromModelRefP



MdlGetDesignFileFromModelRefP

These will help bridge the gap between the two languages. In addition to  stdmdlbltin.dll and stdmdlaccessor.dll, there are other libraries available that will  expose most functions available to MDL in VBA. These are: •

stdbspline.dll for the Bspline curve and surface functions



stdcons.dll for the constraint manager functions



stdimage.dll for the image functions



stdkisolid.dll for the kernel independent solid functions



stdmtg.dll for the manifold topology functions



stdraster.dll for the raster reference functions



stdrdbms.dll for the database functions



stdrender.dll for the rendering functions

One note about the functions that are in these libraries; since they are Pascal  calling sequence functions, they do not handle variable argument lists. So, any  function that uses a variable argument will not be available. The function  templates are available from the MDL Function Reference help document  (MDLAPIFunctionReference.chm) in the MicroStation SDK. Excerpt from msdn.microsoft.com: Traditionally, APIs are written for C and C++ programmers who are building  Windows applications, but the functions in a DLL can be called by other  programming languages, including VBA. Because most DLLs are written and  documented primarily for C and C++ programmers, calling a DLL function 

Dec-09

51

Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

Calling C and MDL Functions

might differ somewhat from calling a VBA function. To work with an API, you  must understand how to pass arguments to a DLL function. Caution: Calling the Windows API and other DLL functions can be hazardous to  the health of your application. When you call a DLL function directly from your  code, you are bypassing some of the safety mechanisms that VBA usually  provides for you. If you make a mistake in defining or calling a DLL function (as  all programmers eventually do), you might cause an application error (also  referred to as a general protection fault, or GPF) in your application. The best  strategy is to save your project before you run your code, and to make sure  you understand the principles behind calls to DLL functions.

Helpful notes This process should by no means be a substitute for using the Object Model. It  should be contained in modules and tested thoroughly. There are no safety checks  to help you with memory allocation issues, and you have no access to the fields of  a data structure.  You can use the VarPtr function to obtain a memory reference to a block of  information. The drawback is that the type of data is unknown, and so, can be  easily corrupted. An advantage can exist if a function can accept NULL as an input  value. To pass strings from VBA to mdl functions that require MSWChar*, you need to  use the StrPtr method. This is because VBA tries to automatically convert  String variables to char *. The scope of these functions should be kept Private to the module so that the  parameters can be adjusted for the specific case. 

Exercise: Displaying a file selection dialog box using the function  mdlDialog_fileOpen

1

If you have not already done so, download and install the MicroStation  SDK from http://www.bentley.com/en‐US/Corporate/Bentley+Partner+Program/ Technology+Partners/MicroStation+SDK.htm

2

In the VBA Project Manager dialog, create and load the project Open_File.

3

Switch to the Visual Basic Editor, insert a module, and create the following  macro, ShowOpen:

Extending Functionality

52

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Calling C and MDL Functions

Private Declare Function mdlDialog_fileOpen Lib _ "stdmdlbltin.dll" _ (ByVal fileName As String, _ ByVal rFileH As Long, _ ByVal resourceId As Long, _ ByVal suggestedFileName As String, _ ByVal filterString As String, _ ByVal defaultDirectory As String, _ ByVal titleString As String) As Long Private m_bCancelEnter As Boolean Private m_flags As Long Private m_FilterIndex As Long Private m_Filter As String Private m_FileName As String Private m_iAction As Integer

Property Let Flags(lFlags As Long) End Property

Property Get Flags() As Long End Property

Public Property Get FilterIndex() As Long FilterIndex = m_FilterIndex End Property

Public Property Let FilterIndex(ByVal lFilterIndex As Long) m_FilterIndex = lFilterIndex End Property

Public Property Get Filter() As String Filter = m_Filter End Property

Public Property Let Filter(ByVal strFilter As String) m_Filter = strFilter End Property

Dec-09

53

Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

Calling C and MDL Functions

Public Property Get FileName() As String FileName = m_FileName End Property

Public Property Let FileName(ByVal strFileName As String) TruncateAtEOS (strFileName) m_FileName = strFileName End Property '

Truncates a buffer to just contain the string that

'

the C function returned.

Function TruncateAtEOS(str As String) As String If str "" Then ' This test avoids exception on zero-length string TruncateAtEOS = Left$(str, InStr(1, str, vbNullChar) - 1) End If End Function

Public Sub ShowOpen() Dim strNewFile As String strNewFile = Space(1024) If mdlDialog_fileOpen(strNewFile, 0, 0, "", m_Filter, _ "", "Select file") = 0 Then TruncateAtEOS (strNewFile) m_FileName = strNewFile End If End Sub

Public Property Get CancelEnter() As Boolean CancelEnter = m_bCancelEnter End Property

Public Property Let CancelEnter(ByVal bCancelEnter As Boolean) m_bCancelEnter = bCancelEnter End Property

Public Property Get Action() As Integer Action = m_iAction

Extending Functionality

54

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Module Review

End Property

Public Property Let Action(ByVal iAction As Integer) m_iAction = iAction End Property

4

Run the macro.

To extend VBA to cover more possibilities, application developers need to be  familiar with using other APIs that are complementary to VBA. 

Module Review Now that you have completed this module, let’s measure what you have learned.

Questions

Dec-09

1

What is the convention for calling C functions from VBA?

2

How can an application access MDL functions and data?

3

Where can a developer find the MDL function declarations needed for  VBA?

55

Copyright © 2009 Bentley Systems, Incorporated

Extending Functionality

Module Review

Extending Functionality

56

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Events Module Overview Often applications will need to respond to some activity in the host environment.  This is often the case in MicroStation, since it is an event machine. It constantly  sends out messages that something is happening.  In order for a macro to take advantage of this environment, the macro needs to  set up methods to be called when certain events happen.

Module Prerequisites •

Understand the concept of events and event‐driven applications.



Ability to create macros implementing commands that add elements to a  model.



Ability to create macros implementing commands that interactively find and  query or modify elements in a model.

Refer to the Course Overview for additional pre‐requisites.

Module Objectives After completing this module, you will be able to:

Dec-09



Create VBA code to listen for and act upon design file open and close  operations.



Create VBA code to listen for and act upon events exposed through the  implementation of interfaces.

57 Copyright © 2009 Bentley Systems, Incorporated

Events

Introductory Knowledge

Introductory Knowledge Before you begin this module, let's define what you already know.

Questions 1

What is the purpose of using the IPrimitiveCommandEvents_Dynamics  method in a Primitive command?

2

Which of the following is not a method of a class that implements the  ILocateCommandEvents interface?

3



ILocateCommandEvents_LocateFilter



ILocateCommandEvents_Dynamics



ILocateCommandEvents_DataPoint



ILocateCommandEvents_Accept 



ILocateCommandEvents_LocateFailed



ILocateCommandEvents_Start

In a Locate command, what ancillary processing might the implemented  interface class perform in its ILocateCommandEvents_LocateReset  method?

Answers 1

IPrimitiveCommandEvents_Dynamics is used to let the command show 

reaction to mouse movements. 2

ILocateCommandEvents_DataPoint

3

Release some of the resources that have accumulated during the locate  process.

Types of Events There are two ways that events are caught in VBA. One is the WithEvents  implementation. The other is by implementing interfaces and adding the class to  the list of things to be called when an event occurs. 

Events

58

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Types of Events

The two events that MicroStation supports as part of the application are  OnDesignFileOpened and OnDesignFileClosed. The rest are available by  adding a class that has the proper interface and method signatures to listen for  the events. You will see a simple macro that will handle both situations.

File events Macros often use MicroStation file open and close events to manage external  references that are file dependent. To set a macro to respond to the  OnDesignFileOpened and OnDesignFileClosed events, the class needs to  declare a variable WithEvents oVariableName As Application. This will  register the class that has this variable to be called when it is loaded and a file is  opened or closed. Private Sub oApplication_OnDesignFileClosed(ByVal DesignFileName _ As String) Debug.Print "application on design file close event" End Sub

Private Sub oApplication_OnDesignFileOpened(ByVal DesignFileName _ As String) Debug.Print "application on design file opened event" End Sub

Interfaces To provide a framework for macros to integrate with MicroStation’s normal  operations, Bentley has built a set of interfaces that classes can implement. When  a class implements an interface, and so is registered with MicroStation, the  methods that are defined by the interface will be called in response to certain  events. This makes MicroStation extensible for most any purpose. For the vast majority of events in MicroStation, special event handlers will need to  be added to the system. To do this, the class must implement the specific  interface that is designed for the task. When a class implements an interface it will  provide methods of a pre‐defined signature that MicroStation can safely call.  As an example, in a class module add the line: Implements IchangeTrackEvents

Dec-09

59

Copyright © 2009 Bentley Systems, Incorporated

Events

Types of Events

Now, in the class, add the calls that are required by the interface to be  implemented: IChangeTrackEvents_BeginUndoRedo – The undo/redo process is starting IChangeTrackEvents_ElementChanged – an Element has changed IChangeTrackEvents_FinishUndoRedo – The undo/redo process is completing IChangeTrackEvents_Mark  – Mark the file to group a set of changes

To establish these methods, the class needs to be listed with the system to be  active. To make the system aware, there should be a method on the class that  represents the system, such as addXXX. This method will take a reference to a  class as a parameter. This class will then be called for the appropriate event.  It may be desirable to use the OnProjectLoad method to fire off the routine that  will register the event listener. There is a parallel method for the unload event  OnProjectUnload that is called when a project is removed. Option Explicit Private oEventHandlers As EventHandlerCls

Sub InstallEventHandlerCls() RemoveEventHandlerCls Set oEventHandlers = New EventHandlerCls AddAttachmentEventsHandler oEventHandlers AddChangeTrackEventsHandler oEventHandlers AddLevelChangeEventsHandler oEventHandlers AddModelActivateEventsHandler oEventHandlers AddSaveAsEventsHandler oEventHandlers AddViewUpdateEventsHandler oEventHandlers End Sub

Sub RemoveEventHandlerCls() If Not oEventHandlers Is Nothing Then RemoveAttachmentEventsHandler oEventHandlers RemoveChangeTrackEventsHandler oEventHandlers RemoveLevelChangeEventsHandler oEventHandlers RemoveModelActivateEventsHandler oEventHandlers

Events

60

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Types of Events

RemoveSaveAsEventsHandler oEventHandlers RemoveViewUpdateEventsHandler oEventHandlers End If Set oEventHandlers = Nothing End Sub

Sub OnProjectLoad() InstallEventHandlerCls End Sub

Sub OnProjectUnload() RemoveEventHandlerCls End Sub

The following interface classes are available: •

IAttachmentEvents — Lets macros monitor all of the changes to reference 

file attachments. •

IBatchConverterEvents — Lets macros monitor events related to 

MicroStation’s Batch Convertor utility. •

IChangeTrackEvents — Lets macros monitor all of the changes that happen 

to DesignFiles during a MicroStation session. •

IEnterIdleEvent — Lets macros receive notification that MicroStation has 

entered an idle state. •

ILevelChangeEvents — Defines the methods MicroStation uses to notify a 

macro of level‐change events. •

ILocateCommandEvents — Lets macros define element location commands. 

This is covered in the module “Building Commands”. •

IModalDialogEvents — Defines the methods MicroStation uses to notify a 

macro when the user opens and closes modal dialogs. •

IModelActivateEvents — Defines the methods MicroStation uses to notify a 

macro of model‐activate events. •

IModelChangeEvents — Defines the methods MicroStation uses to notify a 

macro of model‐change events. •

IPrimitiveCommandEvents — Lets macros define element placement 

commands. This is covered in the module “Building Commands”. •

Dec-09

IRasterEvents — Lets macros monitor all actions applied to rasters.

61

Copyright © 2009 Bentley Systems, Incorporated

Events

Module Review



ISaveAsEvents — Lets macros provide methods that MicroStation calls both 

before and after it it performs any remapping that is required as part of a  SaveAs command. •

IStandardsChecker — Lets macros extend MicroStation’s Standards Checker 

utility. This is covered in the module “Standards Checker Extensions”. •

IViewUpdateEvents — Defines the methods MicroStation uses to notify a 

macro of View update events.  

Exercise: Handle an event 1

In the VBA Project Manager dialog, create and load the project  Running_Element_Count.

2

Switch to the Visual Basic Editor, insert a class module, and implement a  class that will update the element count when a write to file is made.

3

Insert a class module and implement a class that will reset the element  count when the model changes.

Module Review Now that you have completed this module, let’s measure what you have learned.

Questions

Events

1

Name at least five interfaces available to a MicroStation VBA macro?

2

True or False: When a class implements an interface it defines unique  calling signatures for its methods.

3

How can an application work with raster events?

62

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Standards Checker Extensions Module Overview The Standards Checker in MicroStation is an extensible utility enabling the  validation of design file data against a customizable set of standards.  Implementing a simple StandardsChecker extension is a matter of implementing  the IstandardsChecker interface, then having a module that will register the  class as a StandardsCheckerApplication. 

Module Prerequisites •

Understand the purpose of the Standards Checker utility in MicroStation.



Familiar with the operation of the Standards Checker utility.



Ability to create macros that listen for and act upon events.

Refer to the Course Overview for additional pre‐requisites.

Module Objectives After completing this module, you will be able to: •

Develop custom plug‐ins to extend the functionality of the Standards Checker  utility.

Introductory Knowledge Before you begin this module, let's define what you already know.

Dec-09

63 Copyright © 2009 Bentley Systems, Incorporated

Standards Checker Extensions

Implementation

Questions 1

Which events does MicroStation support as part of the application?

2

What functionality does the AttachmentEvents interface class provide?

3

Which interface class defines the methods MicroStation uses to notify a  macro of level‐change events?

Answers 1

OnDesignFileOpened and OnDesignFileClosed

2

The AttachmentEvents class lets VBA macros monitor changes to  reference file attachments.

3

LevelChangeEvents

Implementation The keys to implementing a StandardsChecker extension are to register the class  only once to set up the settings and determine whether the user can interact with  the check process. Standards Checker extensions can be implemented in any COM  language, although only VBA macros are supported in the Power applications  such as PowerDraft. To implement a module for loading the class the code first has to make sure that  there is not an already loaded class and if so unload that before loading the new  one. To do this use the following structure for the module. Public stdCheckerApp As clsStandardsCheckerImpl

Sub OnProjectLoad() AddStdCheckerApp End Sub ‘ ' There is nothing to prevent this program from adding 2 standards ‘ checkers. To prevent that from happening, call RemoveAttachmentsChecker ‘ before adding the checker. ‘ Sub AddStdCheckerApp()

Standards Checker Extensions

64

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Implementation

RemoveStdCheckerApp

Set oSettingsCollection = New SettingCollection oSettingsCollection.init Set stdCheckerApp = New clsStandardsCheckerImpl StandardsCheckerController.AddStandardsChecker stdCheckerApp, 1000 End Sub

Sub RemoveStdCheckerApp() If Not stdCheckerApp Is Nothing Then StandardsCheckerController.RemoveStandardsChecker stdCheckerApp Set stdCheckerApp = Nothing End Sub

Once this module is written, add the .mvba file to the list of Standards Checker  applications by setting the configuration variable MS_STDCHECKERAPPS: MS_STDCHECKERAPPS >  mystdchecker.mvba.

Simple – use the basic framework A class needs to implement the IStandardsChecker interface to use the basic  framework. When implementing this interface, the class will only have a stub for  the GetFixDetail method. The GetFixDetail method will be explored in more  detail later. The IdentityString, DialogString, VersionString and Description  properties are used by the user interface and reporting systems for the Standards  Checker. These will allow the macro to show its name and description and to be  involved in the reporting process.  Not every checker macro will need to have some type of settings. By returning  True for the HasSettings property, the settings button will be added to the  standard user interface. The class needs to return True for the FoundSettings  property if it is capable of operating. If the macro needs to have some settings  before it can operate, then it needs to return False for FoundSettings. Any  macro that returns False for the FoundSettings property is automatically  disabled.

Dec-09

65

Copyright © 2009 Bentley Systems, Incorporated

Standards Checker Extensions

Building Custom Standards Checker Applications

Advanced – use the Fixes optional dialog The next step in the development of Standards Checker extensions is to add the  capability to fix issues as they are found during the check process. To do this, the  checker macro needs to call the ShowCheckerErrorWithFixOptions method  which will call the GetFixDetails method. This method requires the macro to fill a list of possible corrections for the user to  pick from. These “fixes” are then presented to the user in the Standards Checker  user interface. When the user has selected one of the fixes, it is sent back to the  macro which then applies the fix to the element. Once the GetFixDetails  method has returned the value of the ShowCheckerErrorWithFixOptions  method, it is checked and one of the possible actions is taken. The results are then  updated in the report using the StandardsCheckerReport class.

Building Custom Standards Checker Applications One thing that is not apparent about the Standards Checker is the ability to  extend the functionality to check more than just symbology or level definitions. It  is a framework for processing design files. Application developers can use it to  build custom plug‐in solutions to extend the capabilities.  An example of this functionality is the ability to read a corporate standard in a  common file that is read at check time. Since symbology is more complex, only  one type of information can be on one level. Custom interpretation of the  information is required. To build a custom plug‐in, start by creating a new project. In this project, add a  new module. This module will be the entry point for the macro.  The next step is to insert a new class. In the new class, add the line to implement  the IstandardsChecker interface.  The next step is to simply add the required method and property signatures for  the interface. Now that the class to handle the standard checking is in place, add a  subroutine in the module to load the class into the standard checker. An  important note is that the plug‐in can be loaded multiple times. To prevent this,  the macro should unload the class before trying to load the class. To move the  custom plug‐in to the top of the list, use a high priority number (the second  parameter).

Standards Checker Extensions

66

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Building Custom Standards Checker Applications

Option Explicit Public oSettingsCollection As SettingCollection Public stdCheckerApp As clsStandardsCheckerImpl Private oSC As IstandardsChecker

Sub OnProjectLoad() AddStdCheckerApp End Sub

Sub AddStdCheckerApp()

‘ ' There is nothing to prevent this program from adding 2 standards ‘ checkers. To prevent that from happening, call RemoveAttachmentsChecker ‘ before adding the checker. ‘ RemoveStdCheckerApp Set oSettingsCollection = New SettingCollection oSettingsCollection.init Set stdCheckerApp = New clsStandardsCheckerImpl StandardsCheckerController.AddStandardsChecker stdCheckerApp, 1000 End Sub

Sub RemoveStdCheckerApp() If Not stdCheckerApp Is Nothing Then StandardsCheckerController.RemoveStandardsChecker stdCheckerApp Set stdCheckerApp = Nothing End Sub

By implementing the interface, the class code will appear as follows. Implements IStandardsChecker Private Property Get IStandardsChecker_CallForEachModel() As Boolean End Property

Private Sub IStandardsChecker_CreateSettings() End Sub

Dec-09

67

Copyright © 2009 Bentley Systems, Incorporated

Standards Checker Extensions

Building Custom Standards Checker Applications

Private Sub IStandardsChecker_DeleteSettings() End Sub

Private Property Get IStandardsChecker_Description() As String End Property

Private Property Get IStandardsChecker_DialogString() As String End Property

Private Sub IStandardsChecker_EditSettings(ByVal IsReadOnly As Boolean) End Sub

Private Property Get IStandardsChecker_FoundSettings() As Boolean End Property

Private Sub IStandardsChecker_GetFixDetail(Fixes() As String, _ ByVal SelectedFix As Long, _ FixPropertiesLabel As String, _ FixProperties() As String) End Sub

Private Property Get IStandardsChecker_HasSettings() As Boolean End Property

Private Property Get IStandardsChecker_IdentityString() As String End Property

Private Sub IStandardsChecker_RunCheck _ (ByVal ModelToCheck As ModelReference, _ ByVal FirstModel As Boolean, _ ByVal Options As Long) End Sub

Private Property Get IStandardsChecker_VersionString() As String End Property

Standards Checker Extensions

68

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Building Custom Standards Checker Applications

The macro control properties and methods to note here are HasSettings,  EditSettings, FoundSetting, CreateSetting, and DeleteSetting. The  HasSettings method is called by the interface to determine if the macro has  some configurable settings. This will activate the settings button on the user  interface. When the user selects the settings button, the EditSettings method  in the plug‐in will be invoked. Plug‐in settings are stored as a settings element in  the DGN library. If the plug‐in wants to store its settings in the design file, the  CreateSettings method is invoked by the standards macro.  The DeleteSettings method is called to let the plug‐in delete the settings  element. The FoundSettings property is used to tell the macro that the plug‐in  has settings and is capable of running. For a macro to work properly, it must set  FoundSettings to True so that it will be enabled on the user interface. Another  property that a plug‐in should set is CallForEachModel. This tells the macro that  the plug‐in should be called for each model in the design file. The RunCheck method is called when the macro is invoked to check the elements.  When the macro invokes the RunCheck method it will pass in the model that is  being checked, some additional information such as if it is the first (or active)  model, and some options that affect the operation of the plug‐in. In the RunCheck  the plug‐in will do most of its work. The plug‐in will need to iterate through the  elements it will check and, if necessary, invoke the user interface. To invoke the  macro user interface, the plug‐in will call the StandardsCheckerController  method, ShowCheckerError method, or ShowCheckerErrorWithFixOptions to  interact with the user.  ShowCheckerErrorWithFixOptions requires some set up by the macro. The  plug‐in will provide the options that the user can choose from if they want to fix  the element. The plug‐in needs to build a set of “fixes” that will be displayed to  the user in the StandardsChecker user interface. Along with this array of  information, the plug‐in will provide the descriptions and labeling for the user  interface. 

When the user has responded to the prompting, the plug‐in needs to set the  properties for the TotalProblems and FixedProblems that will be used in the  user interface. If the plug‐in wants to add information to the XML report, it uses  the StandardCheckerReport.AddProblem method. The last parameter for this  method lets the report know if the plug‐in has fixed the element. The RunCheck is  the heart of the plug‐in and, as such, will be the method that requires the most  work when implementing a plug‐in. The other methods provide some information about the macro to the standard  interface. The Overstraining property lets the macro add information about the 

Dec-09

69

Copyright © 2009 Bentley Systems, Incorporated

Standards Checker Extensions

Building Custom Standards Checker Applications

plug‐ins that are used in processing the file to the report. The IdentityString  property is used to provide a unique name for the plug‐in. The DialogString  property is applied to the main dialog that the user will select from in the macro.  The Description property is used in report generation from the macro. To demonstrate this process, this sample macro will use the RunCheck method to  process each element in the file. The settings for this plug‐in will determine the  behavior of the plug‐in. The plug‐in will use a collection of rules to determine if  the element is correct. The collection of rules can be thought of as the standard  that the plug‐in is checking. In the plug‐in, the standard is stored in a CSV file that  is opened when the Settings button is pressed on the StandardsChecker user  interface. When the CSV file is opened, the plug‐in will parse the file and build its  collection of rules to apply. As each model is passed into the RunCheck method,  the plug‐in will iterate through the elements of that model. Private Sub IStandardsChecker_RunCheck _ (ByVal ModelToCheck As ModelReference, _ ByVal FirstModel As Boolean, _ ByVal Options As Long) Dim oEnum As ElementEnumerator Dim oCheckElement As Element

If oSettingsCollection.GetSettings.Count = 0 Then MsgBox "Rerun and Pick Settings file first" Exit Sub End If

Set oEnum = ModelToCheck.Scan

Do While oEnum.MoveNext checkSingleElement oEnum.Current Loop

End Sub

Each element is passed into the CheckSingleElement method that is defined in  the plug‐in. The CheckSingleElement method will examine the element and, in  the case of a simple element, it will apply the check to the element. If the element  is complex it will get the components and check them recursively. If the element  passes the check, it allows the StandardsChecker to continue processing.

Standards Checker Extensions

70

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Building Custom Standards Checker Applications

Sub checkSingleElement(ocheckel As Element) Dim oSubEnum As ElementEnumerator Dim oSubEl As Element Dim oSetting As Setting

If ocheckel.IsComplexElement Then Set oSubEnum = ocheckel.AsComplexElement.GetSubElements Do While oSubEnum.MoveNext checkSingleElement oSubEnum.Current Loop Else If ocheckel.IsGraphical And _ ocheckel.Class = msdElementClassPrimary Then Set oSetting = New Setting oSetting.InitFromElement ocheckel If oSettingsCollection.check(oSetting) = False Then ReportBadElement ocheckel End If End If End If End Sub

If the element fails the check it will be passed to the ReportBadElement method  that the plug‐in defines. The ReportBadElement method will invoke the  StandardsCheckerShowErrorWithFixOptions method.  To call this method, the plug‐in will build the fixes array from the possible  combinations that the element uses. The plug‐in uses the GetFixes method to  generate information about the possible fixes.  '

ShowCheckerErrorWithFixOptions calls this to get the data to display

'

in the bottom section of the dialog. It also calls this everytime the

'

user selects a different row in the list of fixes.

' Private Sub IStandardsChecker_GetFixDetail _ (Fixes() As String, _ ByVal selectedFix As Long, _ FixPropertiesLabel As String, _ FixProperties() As String) FixPropertiesLabel = "VBA Example Fix Properties"

Dec-09

71

Copyright © 2009 Bentley Systems, Incorporated

Standards Checker Extensions

Building Custom Standards Checker Applications

Dim oSetting As Setting Dim i As Integer i = oSettingsCollection.GetSettings.Count

ReDim FixProperties(1 To i, 0 To 2) For i = 1 To oSettingsCollection.GetSettings.Count FixProperties(i, 0) = "Symbology Settings" FixProperties(i, 1) = oSettingsCollection.GetSettings.Item(i).ToString FixProperties(i, 2) = oSettingsCollection.GetSettings(i).description Next i

End Sub

When the user selects from the options on the StandardsChecker macro  interface, the selectedFix option is set to one of the available options. The plug‐ in uses this value to determine the process path. The  msdStandardsCheckerReplaceChoiceSkip is set when the plug‐in should  simply skip the element.  The msdStandardsCheckerReplaceChoiceMarkIgnored option lets the plug‐in  mark the element as ignored and the report can have these added so the user can  revisit the element. The msdStandardsCheckerReplaceChoiceFix option tells  the plug‐in that the element can be fixed according to the one of the fixes choices  that the user has selected. The plug‐in can then take the corrective action and use  the AddProblem method to set the element as fixed. Once the element has been  processed the plug‐in will increment the TotalProblems and continue  processing. Private Sub ReportBadElement(oelm As Element) Dim scc As StandardsCheckerController Dim rpt As StandardsCheckerReport Dim response As MsdStandardsCheckerReplaceChoice Dim strDescr As String Dim opts As MsdStandardsCheckerReplaceOptions Dim handlerChoice As MsdStandardsCheckerReplaceChoice Dim selFix As Long Dim columnLabels(0 To 1) As String Dim Fixes() As String Dim oCurrSetting As New Setting Dim i As Integer

Standards Checker Extensions

72

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Building Custom Standards Checker Applications

Dim scp As StandardsCheckerProblem

Set currElement = oelm oCurrSetting.InitFromElement oelm

'StandardsCheckerController.ShowCheckerStatus "Example Status Message" columnLabels(0) = "Symbology Options" columnLabels(1) = ""

i = oSettingsCollection.GetSettings.Count 'set up the list of possible fixes for this element ReDim Fixes(0 To i, 0 To 1)

Fixes(0, 0) = oCurrSetting.ToString:

Fixes(0, 1) = "Current Settings"

For i = 1 To oSettingsCollection.GetSettings.Count Fixes(i, 0) = oSettingsCollection.GetSettings.Item(i).ToString Fixes(i, 1) = _ oSettingsCollection.GetSettings.Item(i).description Next i

strDescr = "Bad Element: " & DLongToString(oelm.ID) & _ ElmToInfoString(oelm)

Set scc = StandardsCheckerController opts = msdStandardsCheckerReplaceOptionCanFix Or _ msdStandardsCheckerReplaceOptionCanIgnore scc.ShowCheckerErrorWithFixOptions response, selFix, _ strDescr, _ "Fixes List Box Label", _ columnLabels, Fixes, 0, _ opts, _ False

Set rpt = scc.Report

If response = msdStandardsCheckerReplaceChoiceSkip Then Set scp = rpt.AddProblem(strDescr, "My Check", False) ' Record the ElementID because it is the only property of an Attachment

Dec-09

73

Copyright © 2009 Bentley Systems, Incorporated

Standards Checker Extensions

Building Custom Standards Checker Applications

‘ that cannot change. If someone writes a program that processes ' the problem report, they can use the ElementID to be certain the ' program accesses the same attachment that the report refers to. scp.AddElementID stdCheckerApp.currElement.ID scp.AddStandard "My Element Checker App", m_libraryID scp.AddVariance "My Symbology", "", oCurrSetting.ToString End If

If response = msdStandardsCheckerReplaceChoiceFix Then Dim aSetting As Setting Set scp = rpt.AddProblem(strDescr, "My Check", True) 'the last parameter will put the check in the fixed column scp.AddStandard "My Element Checker App", m_libraryID scp.AddAction "Fixed Element Symbology" scp.AddElementID stdCheckerApp.currElement.ID If selFix > 0 Then Set aSetting = oSettingsCollection.GetSettings(selFix) Set oelm.Level = _ ActiveDesignFile.Levels.Find(aSetting.Level) oelm.Color = aSetting.Color oelm.LineWeight = aSetting.Weight End If oelm.Redraw oelm.Rewrite scc.FixedProblems = scc.FixedProblems + 1 End If

If response = msdStandardsCheckerReplaceChoiceMarkIgnored Then Set scp = rpt.AddIgnoredProblem("Element ", strDescr, _ "My Check", False) scp.AddAction "Fixed Element Symbology" scp.AddElementID stdCheckerApp.currElement.ID scp.AddStandard "My Element Checker App", m_libraryID scp.AddVariance "My Symbology", "", oCurrSetting.ToString scc.IgnoredProblems = scc.IgnoredProblems + 1 End If

Standards Checker Extensions

74

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Building Custom Standards Checker Applications

'

If the user entered Cancel, tell RunCheck to abort

If response = msdStandardsCheckerReplaceChoiceAbort Then stdCheckerApp.m_aborted = True

scc.TotalProblems = scc.TotalProblems + 1

End Sub

The plug‐in can use the AddedCheckerToStandardsCheckerApps method to add  information to the report and call the AddLibraryToCheckerApp to add a node  to the report. The report’s AddStandardToLibrary method is used to add the  information to the XML data. Private Sub IStandardsChecker_AddedCheckerToStandardsCheckerApps _ (ByVal ApplicationXMLNode As Object) Dim rpt As StandardsCheckerReport ' If the program declares these as IXMLDOMNode, then the program ' can add custom XML data to the report.

If the program declares them

' as IXMLDOMNode then it must also set a reference to Microsoft XML ' v4.0. Dim oLibraryNode As Object ' or IXMLDOMNode

Set rpt = StandardsCheckerController.Report

' m_libraryID is output from AddLibraryToCheckerApp. ' It is used later as input to AddStandard Set oLibraryNode = rpt.AddLibraryToCheckerApp(ApplicationXMLNode, _ StandardsCheckerController.SettingsFile, m_libraryID) rpt.AddStandardToLibrary oLibraryNode, "Element Checker", "Elements" End Sub

The framework that is provided in the IStandardsChecker interface allows the  plug‐in developer to interact with the StandardsChecker user interface and build a  seamless extension. The class that implements the IstandardChecker interface  does not need to be developed in VBA — it can be defined in any language that  supports COM. The StandardsChecker keeps a list of COM objects that it will invoke. The  configuration variable MS_STANDARDCHECKER_APP can be used to automatically  load the plug‐in. If the file name ends in .mvba, it will automatically be added to 

Dec-09

75

Copyright © 2009 Bentley Systems, Incorporated

Standards Checker Extensions

Building Custom Standards Checker Applications

the list of applications that are loaded when the StandardsChecker is invoked by  the user. There are many problems for plug‐ins to solve such as checking for  missing references, etc. 

Exercise: Implement a check 1

Implement the simple missing reference checker.

Questions 1

What are the keys to implementing a StandardsChecker extension? 

2

In an implementation of the IStandardsChecker interface, what is the  purpose of calling the HasSettings method?

3

True or False: A class implementing an IStandardsChecker interface  need not be developed in VBA — it can be defined in any language that  supports COM.

Standards Checker Extensions

76

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Module Review Answers Building Commands Questions 1

What are events?

2

What are the events that are available to the IPrimitiveCommandEvents  interface?

3

What are the events that are available to the ILocateCommandEvents  interface?

4

How does one make use of an interface?

Answers 1

Events are triggered as the user interacts with various parts of  MicroStation.

2

CleanupDataPoint Dynamics Keyin Reset Start

Dec-09

77 Copyright © 2009 Bentley Systems, Incorporated

Module Review Answers

User Interface

3

Accept Cleanup Dynamics LocateFailed LocateFilter LocateReset Start

4

Create a class module that implements the interface. Use the Implements  keyword in the class module and specify the interface object — for  example, Implements IPrimitiveCommandEvents.

User Interface Questions 1

Name at least five standard user interface controls available to VBA  developers?

2

How can an Image Control be used in a dialog?

3

What methods must be included to make a form resizable?

Answers 1

CheckBox ComboBox CommandButton Frame Image ListBox MultiPage OptionButton ScrollBar

Module Review Answers

78

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Working With Non‐Graphic Data

SpinButton ToggleButton TabStrip

2

The SpinButton and ScrollBar can be used for manipulating the image  that is displayed in the Image control. 

3

FindWindow GetWindowLong SetWindowLong

Working With Non‐Graphic Data Questions 1

What is the preferred method to work with an external database?

2

What is required to work with User Data?

3

What tools are used to work with XML data?

Answers 1

DSN data source

2

User attribute ID assigned by Bentley

3

MSXML

Extending Functionality Questions

Dec-09

1

What is the convention for calling C functions from VBA?

2

How can an application access MDL functions and data?

3

Where can a developer find the MDL function declarations needed for  VBA?

79

Copyright © 2009 Bentley Systems, Incorporated

Module Review Answers

Events

Answers 1

The GetCExpressionValue method takes in the “C” expression and,  optionally, the MDL application that is required.  The  SetCExpressionValue method takes in the expression used to set some  value in an MDL application.

2

Import functions from other applicable libraries provided with  MicroStation by using the Declare statement and providing the prototype  for the function call in a Visual Basic module.

3

MDL Function Reference help document (MDLAPIFunctionReference.chm)  in the MicroStation SDK

Events Questions 1

Name at least five interfaces available to a MicroStation VBA macro?

2

True or False: When a class implements an interface it defines unique  calling signatures for its methods.

3

How can an application work with raster events?

Answers 1

IAttachmentEvents IBatchConverterEvents IChangeTrackEvents IEnterIdleEvent ILevelChangeEvents ILocateCommandEvents IModalDialogEvents IModelActivateEvents IModelChangeEvents IPrimitiveCommandEvents

Module Review Answers

80

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Standards Checker Extensions

IRasterEvents ISaveAsEvents IStandardsChecker IViewUpdateEvents

2

False. The class must provide methods of a pre‐defined signature that  MicroStation can safely call.

3

Create a class module that implements an IRasterEvents interface.

Standards Checker Extensions Questions 1

What are the keys to implementing a StandardsChecker extension? 

2

In an implementation of the IStandardsChecker interface, what is the  purpose of calling the HasSettings method?

3

True or False: A class implementing an IStandardsChecker interface  need not be developed in VBA — it can be defined in any language that  supports COM.

Answers

Dec-09

1

Register the class only once to set up the settings and determine whether  the user can interact with the check process.

2

The HasSettings method is called to determine if the macro has some  configurable settings.

3

True.

81

Copyright © 2009 Bentley Systems, Incorporated

Module Review Answers

Standards Checker Extensions

Module Review Answers

82

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Appendix New to MicroStation VBA? Visual Basic for Applications in MicroStation is Bentley’s implementation of the  standard VBA SDK, with extensions that are relevant to the MicroStation  environment. Visual Basic and its sibling, Visual Basic for Applications (VBA), are  modern, Object‐oriented programming languages that are for use by professional  and casual application developers alike. VBA in MicroStation provides an  environment that has previously only been available to MDL/C programmers.    VBA applications can integrate into the standard workflow of MicroStation  applications.

The MicroStationDGN Object Model In order to make the best use of the programming tools, a basic understanding of  the application and its file structure is necessary.  The Application object represents the running instance of MicroStation. This  means that all the features found in the product are accessible to VBA macros. A  review of the Application object shows some important properties. Among  these properties are the ActiveDesignFile, ActiveModelReference, and  ActiveSettings. These represent the current design file, the active model, and  the current settings.  Some other objects that are important to understand are Attachment,  DesignFile, Element, and ModelReference. 

Dec-09



The Attachment object is a model attached as a reference. 



The DesignFile object is the container that holds models. 



The Element object is the base for all elements in the model, these include  visible and non‐visible elements and simple and complex elements. 



The ModelReference object is the container for all the elements. 

83 Copyright © 2009 Bentley Systems, Incorporated

Appendix

System Overview

There can be multiple models in one design file, but only one model is active at a  time. The ModelReference will have Element caches for the graphical elements,  and the DesignFile will have caches for the non‐model and control elements.  The sub‐classes of elements match the types of elements that are in the design  file. In the Application Object there are many methods that can be useful when  developing macros that are computationally complex. Point3d can be used to do  vector math, and the Matrix3d and Transform groups of methods are used to  scale and manipulate elements. In the MicroStation Visual Basic for Applications help document, the Objects topic  provides properties, methods and examples for many of the MicroStation objects.

System Overview Configuration Variables for VBA MS_VBANEWPROJECTDIRECTORY determines the default location for new Visual Basic 

project files. MS_VBASEARCHDIRECTORIES determines the directories in which MicroStation will 

search for projects when they are loaded by name.

Appendix

84

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

System Overview

MS_VBAAUTOLOADPROJECTS and MS_VBAREQUIREDPROJECTS determine which projects 

are automatically loaded at startup time. MS_VBASAVEONRUN determines whether modified VBA projects are automatically 

saved when a VBA macro is executed. MS_VBA_OPEN_IN_MEMORY controls whether MicroStation keeps a project's data 

available by keeping the project's disk file open, or by copying the project into  memory. MS_VBAGUIDREFERENCES identifies DLLs and type libraries to which references will 

be automatically added in newly created projects. MS_VBANAMEDREFERENCES identifies projects to which references will be 

automatically added in newly created projects. MS_STANDARDSCHECKER_APPS holds a list of MDL applications.  If the name of the 

file has .MVBA as the file extension the VBA project will be loaded.

Keyins for VBA Following is a list of MicroStation VBA key‐ins. •

VBA CREATE  — creates and loads a project with the specified  name. The project file will be created with the specified project name as the  root name and the extension .mvba. The file will be located in the directory  specified by the configuration variable MS_VBANEWPROJECTDIRECTORY. If that  configuration variable is not defined and a path is not specified in the key‐in,  the file will be located in ...\Bentley\Program\MicroStation\.



VBA EDIT — switches to the Visual Basic Editor. 



VBA EDIT  — opens the specified project in the Visual Basic 

Editor. If the project is not currently loaded but can be found in the path(s)  specified by the configration variable MS_VBASEARCHDIRECTORIES, it will be  loaded automatically.  •

VBA EXECUTE [project name]  — executes the specified VBA  statement in the context of the specified project. If a project name is not  specified, MicroStation chooses a project to use as the context. There is no  need to specify a context if the statement uses only the MicroStationDGN  object model. The statement is not case‐sensitive.

Example: VBA EXECUTE If ActiveModelReference.Is3D Then MsgBox "Active model is 3D."

Dec-09

85

Copyright © 2009 Bentley Systems, Incorporated

Appendix

COM Client Applications



VBA HIDE — exits the Visual Basic Editor.



VBA LOAD — opens the Load Project dialog.



VBA LOAD  — loads the specified project. If the file path to the 

.mvba file is not specified, then MicroStation searches in the directories  specified by the configuration variable MS_VBASEARCHDIRECTORIES. If a .mvba  file is found with a root name that matches the specified project name, it is  loaded.  •

VBA PAUSE RECORDING — pauses the recording of a macro.



VBA RESUME RECORDING — resumes recording of a previously paused macro.



VBA RUN — opens the Macros dialog.



VBA RUN — runs the specified macro.



VBA RUN [project name] — loads the specified project if it is not 

already loaded and runs the specified macro. You need to include the square  bracket delimiters [ ] with the project name. •

VBA SAVE  — saves the specified project.



VBA SAVEALL — saves all loaded projects.



VBA SHOW EDITOR — switches to the Visual Basic Editor.



VBA SHOW MACROS — opens the Macros dialog.



VBA START RECORDING — starts the recording of a macro.



VBA STOP RECORDING — stops the recording of a macro.



VBA UNLOAD  — unloads the specified project.

COM Client Applications For proprietary MicroStation customizations where the code must be hidden from  the user, developers can build compiled COM client applications (.exe).  MicroStation exposes a type library for use by COM clients in accessing  MicroStation functionality. The basis of this type library is the MicroStationDGN  Object Model. Microsoft’s Visual Basic (VB) development tools — VB6 and VB.NET — can be  used to build COM client applications for MicroStation. When building a COM client application, add a reference to the  MicroStationDGN object, then set a variable to the MicroStationDGN 

Appendix

86

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

ActiveX Controls and DLLs

Application. You can then access all the functionality of the MicroStationDGN  Object Model. At run time, a COM client application attaches to the most recently launched  instance of MicroStation. If MicroStation is not running, the default MicroStation  will start. This has some drawbacks if you use a special workspace or  configuration.

ActiveX Controls and DLLs ActiveX is a framework for defining reusable software components that perform a  particular function or a set of functions in Microsoft Windows in a way that is  independent of the programming language used to implement them. •

An ActiveX Control is a compiled .ocx file that implements user interface  controls more sophisticated than those available in VBA. An example would  be a TreeView control.



An ActiveX DLL is a compiled .dll file that isolates specific logic and  calculations from general application logic in a VBA macro or VB application.

Like standalone COM client applications (.exe) for MicroStation, ActiveX Controls  and DLLs for MicroStation rely on the type library exposed by MicroStation.  Microsoft’s Visual Basic development tools, v6.0 or greater, can be used to build  ActiveX Controls and DLLs. (VB.NET does not support development of ActiveX  Controls and DLLs.) After you build an ActiveX Control or ActiveX DLL you need to register it using the  Windows command regsevr32. To incorporate an ActiveX Object or DLL in a VBA  macro, you need to reference the DLL — select Tools > References in the Visual  Basic Editor. After you do so, you can write VBA code that accesses the ActiveX  Object or DLL. ActiveX Objects and DLLs can even include references to MicroStationDGN  objects. A simple example of an ActiveX DLL that includes such a reference is as  follows. This function is in a VB project, MarksMath, that has a class, Simple, which  contains this code. Public Function GetCurrentDesignFileName() As String Dim oMSApp As MicroStationDGN.Application Set oMSApp = MicroStationDGN.Application

Dec-09

87

Copyright © 2009 Bentley Systems, Incorporated

Appendix

Interface Programming

GetCurrentDesignFileName = oMSApp.ActiveDesignFile.Name End Function

The VBA code looks like this: Sub workwithmarksmath() Dim oMath As MarksMath.Simple Set oMath = New MarksMath.Simple Dim oMathApp As MarksMath.Application Set oMathApp = New MarksMath.Application Dim oString As String oString = oMath.GetCurrentDesignFileName Debug.Print oString End Sub

Interface Programming An Interface is a group of properties, events, and methods that belong to a class.  The class that is implementing the interface must provide an implementation of  each of the properties, events, and methods that are specified by the Interface.

Sample Macros Scanning Sub SimpleScan() Dim oScanCriteria As ElementScanCriteria Dim oElementEnum As ElementEnumerator Dim i As Long i = 0 Set oScanCriteria = New ElementScanCriteria oScanCriteria.IncludeOnlyVisible Set oElementEnum = ActiveModelReference.Scan(oScanCriteria) Do While oElementEnum.MoveNext Debug.Print "Found an Element of type Number " & _ oElementEnum.Current.Type

Appendix

88

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Sample Macros

i = i + 1 Loop Debug.Print "found a total of " & i & "elements" End Sub

Geometry Private Function computeCenterPoint(oEl As LineElement) As Point3d computeCenterPoint = Point3dInterpolate(oEl.Range.Low, 0.5, _ oEl.Range.High) End Function

Private Function ComputeLow(ept As Point3d, npt As Point3d) As Point3d Dim tPt As Point3d tPt = ept

If npt.x < ept.x Then tPt.x = npt.x End If If npt.Y < ept.Y Then tPt.Y = npt.Y End If If npt.Z < ept.Z Then tPt.Z = npt.Z End If

ComputeLow = tPt End Function

Private Function ComputeHigh(ept As Point3d, npt As Point3d) As Point3d Dim tPt As Point3d tPt = ept

If npt.x > ept.x Then tPt.x = npt.x End If

Dec-09

89

Copyright © 2009 Bentley Systems, Incorporated

Appendix

Sample Macros

If npt.Y > ept.Y Then tPt.Y = npt.Y End If If npt.Z > ept.Z Then tPt.Z = npt.Z End If

ComputeHigh = tPt End Function

Private Function ComputeMaxRange(pts() As Point3d) As Range3d Dim oRange As Range3d Dim i As Long

oRange.High = pts(0) oRange.Low = pts(0)

For i = LBound(pts) To UBound(pts) oRange.High = ComputeHigh(oRange.High, pts(i)) oRange.Low = ComputeLow(oRange.Low, pts(i)) Next ComputeMaxRange = oRange End Function

Sub CreateBoundryPoints(aPoints() As Point3d, _ bPoints() As Point3d, _ uOrder As Long, _ vOrder As Long) ReDim bPoints(uOrder * 2 + vOrder * 2) Dim i As Long For i = 0 To uOrder bPoints(i) = Point3dInterpolate(aPoints(0), i / uOrder, _ aPoints(1)) Next Dim x As Long x = 0 For i = uOrder To uOrder + vOrder

Appendix

90

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Sample Macros

bPoints(i) = Point3dInterpolate(aPoints(1), x / vOrder, _ aPoints(2)) x = x + 1 Next x = 0 For i = uOrder + vOrder To (uOrder * 2) + vOrder bPoints(i) = Point3dInterpolate(aPoints(2), x / uOrder, _ aPoints(3)) x = x + 1 Next x = 0 For i = (uOrder * 2) + vOrder To (uOrder * 2) + (vOrder * 2) bPoints(i) = Point3dInterpolate(aPoints(3), x / vOrder, _ aPoints(0)) x = x + 1 Next End Sub

Sub ConvertRangeToPoints(oRange As Range3d, pts() As Point3d) pts(0) = oRange.Low pts(2) = oRange.High pts(1) = oRange.Low pts(1).x = oRange.High.x pts(3) = oRange.High pts(3).x = oRange.Low.x End Sub

Sub testDTM() Dim oSurface As BsplineSurfaceElement, oElement As Element Dim surface As BsplineSurface Dim aFitPoints() As Point3d Dim aNullWeights() As Double Dim oScanCrit As New ElementScanCriteria Dim oEnumerator As ElementEnumerator Dim count As Long, i As Long

' get all text elements (assumed to be DTM atoms)

Dec-09

91

Copyright © 2009 Bentley Systems, Incorporated

Appendix

Sample Macros

oScanCrit.ExcludeAllTypes oScanCrit.IncludeType msdElementTypeLineString Set oEnumerator = ActiveModelReference.Scan(oScanCrit)

'Count points Do While oEnumerator.MoveNext count = count + 1 Loop

ReDim aFitPoints(0 To count - 1)

oEnumerator.Reset i = 0 Do While oEnumerator.MoveNext Set oElement = oEnumerator.Current With oElement.AsLineElement

aFitPoints(i) = computeCenterPoint(oElement) oElement.Redraw msdDrawingModeHilite i = i + 1 End With Loop

Dim oRangeBlock As Range3d

oRangeBlock = ComputeMaxRange(aFitPoints) Dim oShape As ShapeElement Dim aVerts(3) As Point3d ConvertRangeToPoints oRangeBlock, aVerts

Set oShape = CreateShapeElement1(Nothing, aVerts) oShape.Redraw msdDrawingModeHilite ActiveModelReference.AddElement oShape

Dim uOrder As Long Dim vOrder As Long

Appendix

92

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Sample Macros

Dim boundryPoints() As Point3d uOrder = 10 vOrder = 10 'copy the orgdata Dim orgData() As Point3d orgData = aFitPoints

'this function will create some boundry points to keep the surface 'from going nuts! CreateBoundryPoints aVerts, boundryPoints, uOrder, vOrder ReDim Preserve aFitPoints(0 To (count + (2 * uOrder) + _ (2 * vOrder)) - 1) Dim x As Long Dim l As Long l = 0 x = (count + (2 * uOrder) + (2 * vOrder)) - 1 For x = count To UBound(aFitPoints) aFitPoints(x) = boundryPoints(l) l = l + 1 Next 'Compute 10 x 10 LSQ cubic surface (5 minutes) Set surface = New BsplineSurface surface.FromWeightedPointsAndPlane aFitPoints, aNullWeights, _ Transform3dZero, uOrder, vOrder, 4, 4

Set oSurface = CreateBsplineSurfaceElement1(Nothing, surface) oSurface.Color = 3 ActiveModelReference.AddElement oSurface oSurface.Redraw 'reset things? aFitPoints = orgData uOrder = 15 vOrder = 15

CreateBoundryPoints aVerts, boundryPoints, uOrder, vOrder

Dec-09

93

Copyright © 2009 Bentley Systems, Incorporated

Appendix

Sample Macros

ReDim Preserve aFitPoints(0 To (count + (2 * uOrder) + _ (2 * vOrder)) - 1) l = 0

For x = count To UBound(aFitPoints) aFitPoints(x) = boundryPoints(l) l = l + 1 Next 'Compute 30 x 30 LSQ cubic surface (14 minutes) surface.FromWeightedPointsAndPlane aFitPoints, aNullWeights, _ Transform3dZero, uOrder, vOrder, 4, 4

Set oSurface = CreateBsplineSurfaceElement1(Nothing, surface) oSurface.Color = 4 ActiveModelReference.AddElement oSurface oSurface.Redraw

'Compute 30 x 30 LSQ quadratic surface (14 minutes) 'reset things? aFitPoints = orgData uOrder = 30 vOrder = 30

CreateBoundryPoints aVerts, boundryPoints, uOrder, vOrder

ReDim Preserve aFitPoints(0 To (count + (2 * uOrder) + _ (2 * vOrder)) - 1)

l = 0 x = (count + (2 * uOrder) + (2 * vOrder)) - 1 For x = count To UBound(aFitPoints) aFitPoints(x) = boundryPoints(l) l = l + 1 Next surface.FromWeightedPointsAndPlane aFitPoints, aNullWeights, _ Transform3dZero, uOrder, vOrder, 3, 3

Appendix

94

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Sample Macros

Set oSurface = CreateBsplineSurfaceElement1(Nothing, surface) oSurface.Color = 5 ActiveModelReference.AddElement oSurface oSurface.Redraw

'Compute 50 x 50 LSQ quadratic surface (1 hr 45 min) 'reset things? aFitPoints = orgData uOrder = 50 vOrder = 50

CreateBoundryPoints aVerts, boundryPoints, uOrder, vOrder

ReDim Preserve aFitPoints(0 To (count + (2 * uOrder) + _ (2 * vOrder)) - 1)

l = 0 x = (count + (2 * uOrder) + (2 * vOrder)) - 1 For x = count To UBound(aFitPoints) aFitPoints(x) = boundryPoints(l) l = l + 1 Next surface.FromWeightedPointsAndPlane aFitPoints, aNullWeights, _ Transform3dZero, uOrder, vOrder, 3, 3

Set oSurface = CreateBsplineSurfaceElement1(Nothing, surface) oSurface.Color = 6 ActiveModelReference.AddElement oSurface oSurface.Redraw

'Compute 50 x 75 LSQ quadratic surface 'reset things? aFitPoints = orgData uOrder = 50 vOrder = 75

CreateBoundryPoints aVerts, boundryPoints, uOrder, vOrder

Dec-09

95

Copyright © 2009 Bentley Systems, Incorporated

Appendix

Sample Macros

ReDim Preserve aFitPoints(0 To (count + (2 * uOrder) + _ (2 * vOrder)) - 1)

l = 0 x = (count + (2 * uOrder) + (2 * vOrder)) - 1 For x = count To UBound(aFitPoints) aFitPoints(x) = boundryPoints(l) l = l + 1 Next surface.FromWeightedPointsAndPlane aFitPoints, aNullWeights, _ Transform3dZero, uOrder, vOrder, 4, 4

Set oSurface = CreateBsplineSurfaceElement1(Nothing, surface) oSurface.Color = 7 ActiveModelReference.AddElement oSurface oSurface.Redraw

End Sub

Working with other files Sub ScanAndCount() Dim fileName As String Dim oDesignFile As DesignFile Dim oElementCache As ElementCache Dim oEnum As ElementEnumerator Dim oScanCriteria As ElementScanCriteria Dim iSize As Long Dim iCount As Long

Dim oModel As ModelReference Dim i As Long fileName = "d:\data\dwg\g1088-p4-2.dwg"

Set oDesignFile = OpenDesignFileForProgram(fileName, True) For Each oModel In oDesignFile.Models

Appendix

96

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

Sample Macros

i = 0 Set oElementCache = oModel.GraphicalElementCache iCount = oElementCache.Count Set oScanCriteria = New ElementScanCriteria Set oEnum = oElementCache.Scan(oScanCriteria) Do While oEnum.MoveNext Debug.Print "Found an Element of type Number " & _ oEnum.Current.Type i = i + 1 Loop Debug.Print "Found " & i & "elements in this file " & _ oModel.name Next

oDesignFile.Close End Sub

Dynamic user interface Option Explicit Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, _ ByVal lpWindowName As Any) As Long Private Declare Function GetWindowLong Lib "user32" Alias _ "GetWindowLongA" _ (ByVal HWND As Long, _ ByVal nIndex As Long) As Long Private Declare Function SetWindowLong Lib "user32" Alias _ "SetWindowLongA" _ (ByVal HWND As Long, _ ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long

Private Const WS_THICKFRAME = &H40000 Private Const GWL_STYLE = (-16)

Private Sub UserForm_Activate() Dim lngFrmHWND As Long Dim lngStyle As Long

Dec-09

97

Copyright © 2009 Bentley Systems, Incorporated

Appendix

Sample Macros

Dim lngRetVal As Long

lngFrmHWND = FindWindow("ThunderDFrame", Me.Caption) lngStyle = GetWindowLong(lngFrmHWND, GWL_STYLE) lngRetVal = SetWindowLong(lngFrmHWND, GWL_STYLE, lngStyle Or _ WS_THICKFRAME) End Sub

Private Sub UserForm_Resize()

'ListBox2.Top = Me.Top ListBox2.Left = 1 ListBox2.Width = Me.Width - 9 ListBox2.Height = Me.Height / 2 - 5

Label1.Top = ListBox2.Height + 2 Label1.Height = 5 Label1.Width = ListBox2.Width

ListBox1.Top = ListBox2.Height + Label1.Height + 5 'ListBox1.Height = Me.Height - (ListBox2.Height + Label1.Height + 18) ListBox1.Height = Me.Height / 2 - 10 ListBox1.Left = ListBox2.Left ListBox1.Width = ListBox2.Width Debug.Print "Height: " & Me.Height & " Width:" & Me.Width Debug.Print "the upper list box is "; ListBox2.Height; _ " tall starts at "; ListBox2.Top Debug.Print "the lower list box is "; ListBox1.Height; _ " tall starts at "; ListBox1.Top End Sub

Appendix

98

Copyright © 2009 Bentley Systems, Incorporated

Dec-09

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF