This page lists some solutions to common MicroStation VBA (MVBA) and VB problems. Few of these tips are original: some are repeated from Microsoft VB or VBA documentation, and some are paraphrased from the MVBA documentation. Unless declared explicitly, the content applies equally to VB or MVBA. Tips are published as examples and are not necessarily working code.
A good place to post questions about MicroStation VBA is the Bentley Communities MicroStation Programming Forum.
Q Where is the help file for MicroStation VBA?
A
The MicroStation VBA help file is MicroStationVBA.chm
.
The .chm
extension tells you that it's a compiled HTML help file.
MicroStationVBA.chm
is installed in the same folder as the MicroStation executable (MicroStation.exe
).
In other words, if you can find MicroStation, you can find VBA help.
The default location of MicroStation (and VBA help) varies according to the installation. Here are a couple of locations that you may find …
Product | Operating System | Location |
---|---|---|
MicroStation | 64-bit | C:\Program Files\Bentley\MicroStation |
CONNECT | C:\Program Files\Bentley\MicroStation CONNECT Edition Update 2 |
MicroStation VBA help is comprehensive. It documents every object in detail, and provides plenty of examples …
Q How do I get some basic information about the current file that I'm working with?
A
A ModelReference
doesn't have a file name because it's one of many models
that live inside a DGN file, which in VBA is a DesignFile
object.
However, that DesignFile
has a file name and path.
So the solution is to find the ModelReference
's parent DesignFile
,
which is straightforward, and ask its name …
' ---------------------------------------------------------------------
' GetDgnFileName
' Returns: String containing the file path of the given model
' ---------------------------------------------------------------------
Public Function GetDgnFileName(ByVal modelRef As ModelReference) As String
GetDgnFileName = vbNullString
On Error GoTo err_GetDgnFileName
GetDgnFileName = modelRef.DesignFile.FullName
Exit Function
err_GetDgnFileName:
MsgBox "Error no. " & CStr(Err.Number) & ": " & Err.Description & vbNewLine & _
"Caused by " & Err.Source, vbOKOnly Or vbExclamation, "Get DGN File Name Error"
End Function
Here's a test subroutine that gets the active model's file path …
Public Sub TestDgnFileName()
Dim path As String
path = GetDgnFileName(ActiveModelReference)
Debug.Print "DGN File Path: " & path
End Sub
A
File Dimension is one of those mysterious TCB things: tcb->ndices
that has survived, for no apparent reason, in MicroStation V8.
Here's more information about the TCB,
and here's an example procedure that reveals the file dimension …
' ---------------------------------------------------------------------
' IsThreeD
' Returns: True if the active file is 3D, 2D otherwise
' ---------------------------------------------------------------------
Public Function IsThreeD() As Boolean
Select Case CLng(GetCExpressionValue("tcb->ndices"))
Case 3
IsThreeD = True
Debug.Print "File is 3D"
Case 2
Debug.Print "File is 2D"
IsThreeD = False
Case Else
MsgBox "DGN is neither 2D nor 3D!", vbCritical Or vbOKOnly, "Invalid File Dimension"
End Select
End Function
However, with MicroStation V8, File Dimension doesn't mean anything. A DGN file contains one or more models (or cells), each of which may be 2D or 3D. Suppose, for example, that you have a cell library containing three models, one 3D and two 2D. Is that cell library a 2D library or a 3D library?
You can get the dimension of a model like this …
Debug.Print "Model is " & Iif (oModel.Is3d, "3D", "2D")
In older versions of MicroStation VBA that property of a model was not available, and we had to use an MDL call to get that information …
Declare PtrSafe Function mdlModelRef_is3D Lib "stdmdlbltin.dll" ( ByVal modelRef As Long ) As Long Public Function IsModel3d (ByVal oModelRef As ModelReference) As Boolean If (0 <> mdlModelRef_is3D (oModelRef.MdlModelRefP)) Then IsModel3d = True Else IsModel3d = False End If End Function
A As of MicroStation XM, VBA contains no objects concerned with DGN file history. But there are ways around that limitation: here are a couple of suggestions …
One approach is to use the MDL functions declared below.
If all you want to know is whether history is enabled or not,
here's a simple VBA function HistoryExists
that wraps the MDL functions.
It returns a Boolean
value that indicates the state of history.
' --------------------------------------------------------------------- ' MDL function declarations ' ---------------------------------------------------------------------
Declare PtrSafe Function mdlHistory_exists Lib "stdmdlbltin.dll" (ByVal pFile As Long) As Long Declare PtrSafe Function mdlModelRef_getDgnFile Lib "stdmdlbltin.dll" (ByVal modelRef As Long) As Long Declare PtrSafe Function mdlModelRef_getActive Lib "stdmdlbltin.dll" () As Long' ---------------------------------------------------------------------
Public Function HistoryExists() As Boolean HistoryExists = False Dim exists As Long exists = mdlHistory_exists(mdlModelRef_getDgnFile(mdlModelRef_getActive())) HistoryExists = exists <> 0 End Function
Yongan Fu, of Bentley Systems, suggested using a Property Handler …
Sub TestDesignHistoryOn() Dim oPH As PropertyHandler Dim revCnt As Integer Set oPH = CreatePropertyHandler(ActiveDesignFile) oPH.SelectByAccessString "DesignRevisionCount" revCnt = oPH.GetValue If revCnt = 0 Then MsgBox "Design History is OFF" Else MsgBox "Design History is ON" End If End Sub
Q How can I include a ColorPicker or ColorChooser control in my UserForm?
A Microsoft VBA knows nothing about the application it's used with. The controls available to you as a UserForm designer are those provided with VBA and any that may be provided in control libraries.
Plain old VBA is generic: it doesn't know about CAD and therefore doesn't provide tools for browsing a colour palette or picking a colour from a palette.
In the past, Bentley have provided two controls for colour manipulation: ColorPicker and ColorChooser. However, those controls were unsupported and are no longer available.
As an alternative, look at this article about Using a Microsoft Common Control Color Dialog …
Q How can I tell if MicroStation has an active database connection?
A
Use the MDL function mdlDB_isActive()
.
This example by Jerry Walter at Bentley Systems shows you how …
Declare PtrSafe Function mdlDB_isActive Lib "stdmdlbltin.dll" () As Long' ---------------------------------------------------------------------Sub isDbAttachedTest() If IsDbAttached() Then MsgBox "Database is attached", vbOKOnly, "Database" Else MsgBox "Database is not attached", vbOKOnly, "Database" End If End Sub' ---------------------------------------------------------------------Function IsDbAttached() As Boolean IsDbAttached = CBool(mdlDB_isActive()) End Function
Q How do I run a VBA macro at startup
A You can run a VBA macro as MicroStation starts up, or each time you open a design file.
The answer is at the MicroStation Oracle: Ask Inga.
Q When should I use parentheses in a procedure call? When should I not use parentheses in a procedure call?
A A procedure in VB and VBA is either a Function or a Subroutine. A Function returns a value, a Subroutine returns nothing. When a procedure accepts one or more parameters, you pass a variable or value to the procedure.
Suppose we have a simple Subroutine that modifies a variable. This example multiplies the passed variable by a passed value …
Sub Multiply (ByRef change As Double, ByVal value As Double) change = change * value End Sub
You might call the Subroutine like this …
Dim variable As Double
Const multiplier As Double = 2.5
variable = 2.0 ' VB changes this to 2# because It Knows Best
Multiply variable, multiplier
But, if you call it like this …
Multiply (variable, multiplier)
The VB syntax checker doesn't like the parentheses and highlights the line in red to indicate its anger. The IDE may pop a message box with this enigmatic admonishment: Compile Error Expected:=
However, you may invoke the subroutine like this, enclosing the arguments in parentheses and using the Call
keyword …
Call Multiply (variable, multiplier)
With the Call
keyword, the VB syntax checker accepts the parentheses. Here's a quotation from the MVBA online help that may, or may not,
clarify this point for you …
Call
keyword when calling a procedure.
However, if you use
the Call
keyword to call a procedure that requires arguments,
argumentlist must be enclosed in
parentheses. If you omit the Call
keyword,
you also must omit the parentheses around
argumentlist.
Suppose we have a simple Function that modifies a variable. This example multiplies the passed variable by a passed value and returns the new value …
Function Multiply (ByVal original As Double, ByVal value As Double) Multiply = original * value End Function
You might call the Function like this …
Dim variable As Double
Const multiplier As Double = 2.5
variable = 2.0 ' VB changes this to 2# because It Knows Best
Multiply variable, multiplier
The code is perfectly valid and perfectly useless. The syntax is fine, so the VB editor doesn't complain. However, you're not using the returned value, so why invoke the function?
Let's try again, this time assigning the value returned by the function to a variable …
Dim variable As Double Dim result As Double Const multiplier As Double = 2.5 variable = 2.0' VB changes this to 2# because It Knows Best
result = Multiply variable, multiplier
VB doesn't like that syntax for a function: you must enclose the function arguments in parentheses when you assign the result. Here's the correct invocation …
Dim variable As Double Dim result As Double Const multiplier As Double = 2.5 variable = 2.0 result = Multiply (variable, multiplier)
The VB syntax requires the parentheses around the arguments to a function call. Here's a quotation from the MVBA online help that may, or may not, clarify this point for you …
You are not required to use theCall
keyword when calling a procedure.
However, if you use the Call
keyword to call a procedure that requires arguments,
argumentlist must be enclosed in parentheses.
If you omit the Call
keyword, you also must omit the parentheses around argumentlist.
If you use either Call
syntax to call any intrinsic or user-defined function,
the function's return value is discarded.
The last sentence means that, if you Call
a function, there's no way to obtain its return value.
So this invocation is pointless if you want to know the answer …
Dim variable As Double
Dim result As Double
Const multiplier As Double = 2.5
variable = 2.0
Call Multiply (variable, multiplier) ' Where's my return value?
By the way, a Function defined in a class is known as a Method of that class. The world of object-oriented-design (OOD) has invented its own jargon: refuse to be intimidated!
Q How do I tell MicroStation to use a file when the file name includes spaces?
A We often need to tell MicroStation about a file when changing a setting. For example, when you want to assign a colour table you must pass the full path of the table file. When the file path contains spaces you must wrap the entire path in double-quote characters. Otherwise, the spaces confuse MicroStation.
Here's a simple function that wraps a string in double-quote characters …
'-------------------------------------------------------------
' DoubleQuote
' Wraps a string in double-quote marks
'-------------------------------------------------------------
Public Function DoubleQuote(ByVal s As String) As String
Const sDOUBLE_QUOTE As String = """"
DoubleQuote = sDOUBLE_QUOTE & s & sDOUBLE_QUOTE
End Function
Here's how you might call that function …
Dim fileName As String
fileName = "N:\Projects\New Project\Color Tables\masterplan.tbl"
Debug.Print "Raw file name: " & fileName
Dim quotedName As String
quotedName = DoubleQuote (fileName)
Debug.Print "Quoted file name: " & quotedName
Dim keyin As String
keyin = "print pentable attach " + quotedName
Debug.Print "Keyin: " & keyin
' Assign MicroStation color table
CadInputQueue.SendCommand keyin
Q How do I change MicroStation setting XYZ using VBA?
A Record a VBA macro as described while you manually change the setting. Usually, you will find some cryptic code in the recording that you can copy and paste into another macro.
Q I'm confused by objects and User-Defined Types. They both support dot notation, but how do I know when and where to put that • dot?
A
MVBA makes extensive use of objects and User-Defined Types (UDTs). MicroStation's geometric element types
are represented by classes: when you use a variable that represents a class you have
created an object. The Set
keyword is exclusive to objects. If you omit the Set
keyword,
your code will compile but not execute: you will receive a run-time error …
Dim oLine As LineElement' LineElement is a class provided by MVBA
Dim vertices (0 To 1) As Point3d' Point3d is a user-defined-type provided by MVBA
' Assign values to vertex 1 and vertex 2 vertices(0).X = 10 vertices(0).Y = 10 vertices(0).Z = 0 vertices(1).X = 20 vertices(1).Y = 20 vertices(1).Z = 0' The next two lines are accepted by the VB editor
Set oElement = Application.CreateLineElement1 (Nothing, vertices) oElement = Application.CreateLineElement1 (Nothing, vertices)' Run-time error!
As you probably noticed in the above example, we used an array of Point3d
to supply a vertex list
to the CreateLineElement1 method. A Point3d
is a UDT pre-defined by MVBA. It's equivalent to this definition
in your own code …
Type Point X As Double y As Double z As Double End Type
A UDT is used like a primitive data type such as an Integer
, Double
, etc.
It's not a class, and it's incorrect to confuse it with a class …
' Declare a variable of type Point
Dim point As Point' Use a point variable
point.X = 1234 point.Y = 2345 point.Z = 0
Unfortunately, the VB editor doesn't complain when you confuse a UDT with a class. It accepts this code when you type it but rejects at compile-time …
Dim point As Point
' Use a point variable incorrectly with Set keyword
Set point.X = 1234
Set point.Y = 2345
Set point.Z = 0
The worst thing about this error is the misleading message from VB: Compile error: Object required. The wording makes you think that you've used an object incorrectly, whereas the real mistake is attempting to use a UDT as if it were an object.
Because UDTs are similar to built-in data types, you can legally assign a variable to another variable provided each is declared as the same UDT. You can't do this with an object …
' Declare two variables of type Point
Dim point1 As Point Dim point2 As Point point1.X = 1234 point1.Y = 2345 point1.Z = 0' Assign one point to another
point2 = point1' point2 now has the same X, Y, Z values as point1
Note that I've defined the Point
type purely for illustration. With MVBA,
you should liberally sprinkle your code with variables declared as Point3d
& Point2d
data types. Those types are pre-defined for you by the kind folks at
Bentley Systems.
Q How do I test whether a file really exists?
A Microsoft's Scripting Runtime library is invaluable. It provides …
Here's a short example that illustrates how to tell if a file exists or not. You provide a full file path, and the function tells you (by its Boolean True or False result) if the file exists …
' ---------------------------------------------------------------------
' FileExists
' The code in this procedure uses the Microsoft Scripting Runtime library.
' Use the Tools|References menu to add that library (scrrun.dll) to your VBA project
' Returns: True if the file exists
' ---------------------------------------------------------------------
Public Function FileExists(ByVal fileName As String) As Boolean
Dim oFileSystem As New Scripting.FileSystemObject
FileExists = oFileSystem.FileExists(fileName)
Set oFileSystem = Nothing
End Function
Q How do I verify during development that some value is correct?
A
VB and MVBA make it easy to be a sloppy programmer. However, help is at hand!
The Debug
object provides two useful methods: Debug.Print
and Debug.Assert
.
Both methods only work while you, the programmer, are stepping through code in debug mode or running from the IDE.
Your user will not see the results of the Debug
object.
Debug.Print
does what it says on the tin: it prints whatever text you tell it to print.
The text is written to VBA's Immediate window.
Debug.Assert
tests whatever you pass to it for Boolean
True
or False
.
If the argument fails the test (i.e. it evaluates to False
) then your program halts.
Here's an example that verifies that you have passed a valid file name …
' --------------------------------------------------------------------- ' Start here: this procedure first tests a file that should exist, ' regedit.exe in your Windows folder (typically C:\Windows). ' Next it tests for a non-existent file: ' VBA will halt executiong during debug at the Debug.Assert statement ' ---------------------------------------------------------------------
Sub TestAssert() AssertExample Environ("WINDIR") & "\regedit.exe"' File exists
AssertExample "C:\nonexistent"' File does not exist
End Sub' ---------------------------------------------------------------------
Sub AssertExample(ByVal fileName As String) Debug.Print "Assert test on '" & fileName & "'" Debug.Assert FileExists(fileName) End Sub
Q I used to be a sloppy programmer, but I want to reform my style. How do I go about achieving that goal?
A VB and MVBA make it easy to be a sloppy programmer. One way is to let you use a variable without declaring it first …
skunk = 1234' skunk is an Integer
skunk = 1234.5' skunk is a Double
skunk = "abc"' skunk is a String
Save your self trouble! Put the Option Explicit
statement at the beginning of
every module you write …
Option Explicit
skunk = 1234 ' Compile Error: Variable not defined
VB now wants you to declare each and every variable, so the compiler knows its data type and can detect an inappropriate assignment. Well, most of the time …
Option Explicit Dim skunk As Integer skunk = 1234' OK
skunk = 1234.5' Runs, but what is in variable skunk now?
skunk = "abc"' Run-time error
The second assignment was to test if you're still awake. The compiler accepts the assignment of a
Double
value (1234.5
) to the Integer
variable skunk
.
At run-time, VB truncates the floating-point number to fit into your Integer
variable,
so skunk
contains the value 1234
. In other words, your data have been silently mangled
at run-time.
You can automate Option Explicit
in the Options dialog of the VB IDE: select this
from the Tools menu and toggle the check-box Require Variable Declaration. Once you've
done this, VB writes Option Explicit
at the start of each new module …
Q I place a cell using VBA, but it appears as a dot. What happened?
Dim scale As Point3d Dim origin As Point3d origin.x = 100 origin.y = 200 origin.z = 0 Dim oCell As CellElement Set oCell = Application.CreateCellElement2("example", origin, scale, False, Nothing)
A
Visual Basic for Applications (VBA) tries to be your friend.
It initialises variables for you.
Unfortunately, VBA knows nothing about 3D geometry: it is ignorant about points, vectors, transforms, and matrices.
If you initialise your scale
variable to zero (or let VBA initialise it to zero for you), then any object scaled using that variable will have zero size.
The proper initialisation for a scale is unity.
MicroStation VBA offers the convenient method Point3dOne
,
which sets the X, Y and Z members of a Point3d data type to 1.0
.
What happened in the above example is that the author declared a Point3d
variable named scale
to store the scale of the cell.
Probably, she planned to set scale
to a suitable value as she revised her code.
Unfortunately, VBA initialised scale
to zero.
Placing a cell with scale zero results in a rather small object.
MicroStation shows it as a dot, and you can use the Analyse Element tool to see that it really is a cell, but with negligible dimensions.
Probably the default value for scale should be unity, which you can achieve like this …
Dim scale As Point3d
scale = Point3dOne ' all components 1.0
Another trap for the uninitiated is a rotation matrix
.
A rotation in MicroStation VBA is expressed not in degrees but by a Transform
.
The Transform
data type is provided with MicroStation VBA to store rotation matrices and other transform matrices.
In 3D it's inconvenient to use simple rotations (and 2D is just a special case of 3D, but you knew that).
Unfortunately, a Transform
initialised to zero has no meaning: it's mathematically incompetent.
If you let VBA initialise a Transform
for you, then expect unexpected results.
Instead, assign a meaningful value to your rotation
variable like this …
Dim rotation As Transform
rotation = Transform3dIdentity ' zero rotation
Now, you can use the properly initialised scale
and rotation
variables …
Dim scale As Point3d scale = Point3dOne' all components 1.0
Dim rotation As Transform rotation = Transform3dIdentity' zero rotation
Dim origin As Point3d origin.x = 100 origin.y = 200 origin.z = 0 Dim oCell As CellElement Set oCell = Application.CreateCellElement2("example", origin, scale, False, rotation)
With meaningful initialisation of variables scale
and rotation
, the cell placement works as expected.
Q How do I set the caption of MicroStation's main window?
A
All VBA applications provide an Application
object.
The Application
object is the root of the VBA hierarchy and is the interface with Windows.
The MicroStation main window is a Windows window, if you'll pardon the excessive fenestration.
Therefore, use the Application
object to change the main window caption.
Here's a code sample, probably the simplest you'll find on this page …
Sub TitleTest() SetWindowCaption "LA Solutions VBA Example" End Sub Sub SetWindowCaption(ByVal caption As String) Application.caption = caption End Sub
Q Why does Windows prompt me for an installation CD when I run my VBA macro?
A The problem arises because various products that install VBA may have implemented slightly different versions. Microsoft's installer is attempting to repair what it thinks is a damaged Office installation. Because MicroStation delivers VBA, it's causing a version clash with Office.
Microsoft have provided an installer patch to fix this problem. There's more information in this Bentley Tech Note.
Q What is the maximum number of vertices in a line or shape?
A The answer is 5,000 although I don't see this mentioned in the VBA help. However, it is documented in MDL and there's even a function to return the value, so we can use it in VBA like this …
' MDL function declaration
Declare PtrSafe Function mdlElement_maxLineStringPoints Lib "stdmdlbltin.dll" ( ) As Long' Return the maximum vertex count in a line or shape
Function MaxLineStringPoints () As Integer MaxLineStringPoints = mdlElement_maxLineStringPoints () End Function' Test vertex count function
Sub TextMaxVertexCount () Debug.Print "Max line vertex count=" & CStr(MaxLineStringPoints()) End Sub
If you want to create a shape or line having more than the maximum number of vertices,
you should create a number of lines (ChainableElements
) having 5,000 or fewer vertices, then combine them into a
ComplexStringElement
or ComplexShapeElement
.
The following VBA methods will help you …
CreateComplexShapeElement1
CreateComplexShapeElement2
CreateComplexStringElement1
CreateComplexStringElement2
Q How can I tell if a named cell exists in a library?
A
Before you create a CellElement
, you want to be sure it exists in a currently-attached
Cell Library.
This article about cells and VBA shows you how to check that a cell exists in a cell library.
Sometimes you need to use a function implemented in a Dynamically Linked Library (DLL).
For example, you can use Win32 Windows functions by calling functions implemented in Microsoft's kernel32.dll
,
which you will find in the C:\Windows\System32
folder.
Or you might want to use an MDL function, provided by one of the DLLs in the \MicroStation
folder.
If your VBA project is located in some other folder, how does VBA find the DLL that implements the function you want to call?
Q How Does Windows Find a DLL?
A Windows has a well-defined search order when it looks for a DLL …
GetSystemDirectory
function retrieves the path of this directory
GetWindowsDirectory
function retrieves the path of this directory
PATH
environment variable
Here's the original DLL search article on the Microsoft web site!
However, Microsoft has complicated things further by inventing a safe DLL search mode. Safe DLL search mode is intended to reduce security risks. Unfortunately, from the VBA developer's point of view, it adds complexity. The key difference is that the current folder is searched after the system folders.
GetSystemDirectory
function to get the path of this directory
GetWindowsDirectory
function to get the path of this directory
PATH
environment variable.
Note that this does not include the per-application path specified by the App Paths registry key.
The App Paths key is not used when computing the DLL search path
Here's the DLL safe search article on the Microsoft web site!
You can complicate things by calling an MDL function in VBA code written in another application. MicroStation VBA lets you call MDL functions. Sometimes you need to do this to obtain some obscure functionality that is not available in VBA.
For example, suppose you want to use MDL function mdlModelRef_isActiveModel. First, you must declare it, near the beginning of your VBA module, like this …
Declare PtrSafe Function mdlModelRef_isActiveModel Lib "stdmdlbltin.dll" ( ByVal modelRef As Long ) As Long
The above declaration informs VBA of the arguments the function requires, its return value, and the
library (Lib
) where it can be found. In this case the library is stdmdlbltin.dll
,
which you will find in the MicroStation folder.
VBA can also find stdmdlbltin.dll
because that DLL is in the same folder as ustation.exe
,
the MicroStation executable that owns the memory context in which VBA executes.
If the DLL were somewhere else, then VBA might not be able to find it.
Suppose you are writing a VBA macro in Excel.
You have correctly referenced MicroStationDGN.Application
,
so Excel can find the MicroStation VBA objects.
However, Excel doesn't know how to find MicroStation DLLs.
If your VBA code contains a call to an MDL function,
then Excel VBA probably won't find it.
You have to tell Excel where it can find the MicroStation DLLs.
To accomplish that, add the location of ustation.exe
to the Windows PATH
variable.
Then Excel VBA will be able to find the DLL, following the rules of the
Windows Search Paths.
Q How do I extract the words from a text string?
A
You need VB's Split
function. Split
converts a text string into an array of strings.
It uses a separator string that you specify to work out how the source string should be carved up.
A common requirement is to divide a string where the words are separated by space characters. You would write code something like this …
Dim strSource As String Dim strWords() As String Const strSeparator As String = " " strSource = "Divide this string into words" strWords = Split (strSource, strSeparator) Dim i As Integer, _ nWords As Integer nWords = UBound (strWords) - LBound (strWords) + 1 Debug.Print "strWords array contains " & CStr (nWords) & " words" For i = LBound (strWords) To UBound (strWords) Debug.Print "Word [" & CStr (1 + i) & "]='" & words(i) & "'" Next i
The opposite of Split
, by the way, is Join
.
Q How can I find a file using VB?
A The MDL mdlFile_find function searches for files in folders indicated by a configuration variable. There's an article about finding files using that MDL function.
Q VB's Format()
and Date()
functions provide answers to common questions along
these lines …
A
Suppose you want to obtain today's date: VB and VBA provide a Date
data type and various functions
that manipulate dates. The Now()
function returns the current date and time from your
computer's clock.
Here's an example …
Sub TodaysDate()
Dim strDate As String
Dim oDate As Date
oDate = Now()
strDate = Format(oDate, "Medium Date") ' or "Short Date" or "Long Date" or your own custom date format
Debug.Print "Today's date: " & strDate
End Sub
Here are some examples of date format strings for the date Friday, 20 January 2017 …
Format | Comment | Example | Result |
---|---|---|---|
yyyy | 4-digit year | Format (Now(), "yyyy") | 2017 |
yy | 2-digit year | Format (Now(), "yy") | 17 |
mmmm | full month name | Format (Now(), "mmmm") | January |
mmm | short month name | Format (Now(), "mmm") | Jan |
mm | numeric month | Format (Now(), "mm") | 01 |
dddd | full day name | Format (Now(), "dddd") | Friday |
ddd | short day name | Format (Now(), "ddd") | Fri |
dd | numeric day | Format (Now(), "dd") | 20 |
dd-mmm-yyyy | custom date | Format (Now(), "dd-mmm-yyyy") | 20-Jan-2017 |
mmm/dd/yy | custom date | Format (Now(), "mmm/dd/yy") | Jan/20/17 |
yyyymmdd | custom date | Format (Now(), "yyyymmdd") | 20170120 |
A
VB and VBA provide a number of functions that operate on Date
data. For example, if you want to
calculate the date 90 days from now, you could use the DateAdd()
function. The DateDiff()
function calculates the difference between two dates. The following example shows the difference between
today's date and the fourth of July 2007 …
Function ElapsedTimeSince4thJuly2007() As Long
Dim strDate As String
Dim oDate1 As Date, _
oDate2 As Date
Dim elapsed As Long
oDate1 = #7/4/2007#
oDate2 = Now()
elapsed = DateDiff("d", oDate1, oDate2) ' Compute difference in days
If (0 < elapsed) Then
Debug.Print "It is " & CStr(elapsed) & " days after " & Format(oDate1, "Medium Date")
Else
Debug.Print "There are " & CStr(elapsed) & " days before " & Format(oDate1, "Medium Date")
End If
ElapsedTimeSince4thJuly2007 = elapsed
End Function
Q How do I set an element's range in VBA?
A The range of an element is an imaginary box around the object. MicroStation uses each element's range to acquire summary information when it doesn't need to know the exact details of an element's geometry. For example, when updating a view, MicroStation needs to know which elements are contained by that view: it's far quicker to perform an approximate calculation using each element's range than to perform some complex geometrical analysis.
The MDL function mdlElmdscr_validate()
recalculates an element's range.
Here's how to call it from VBA …
' --------------------------------------------------------------------- ' MDL function declarations (copy this section to the beginning of your VBA module) ' ---------------------------------------------------------------------
Declare Sub mdlElmdscr_validate Lib "stdmdlbltin.dll" (ByVal p As Long, ByVal modelRef As Long)' --------------------------------------------------------------------- ' SetElementRange ' Invoke MDL function to validate an element, which has the effect of ' recalculating the element's range ' Returns: Nothing ' ---------------------------------------------------------------------
Sub SetElementRange(ByVal oElement As Element, ByVal oModel As ModelReference) mdlElmdscr_validate oElement.MdlElementDescrP, oModel.MdlModelRefP End Sub
The note about formatting numbers has been expanded and moved to its own
numeric formatting with VBA page.
It illustrates Microsoft's Format
function.
Q How do I convert an Arc or Curve element to a Line String?
A
The Element.ConstructVertexList()
method provides a way to simplify or stroke a curve to an array of vertices.
Once you have an array of vertices, you can analyse it or convert it into another element, such as a Line String or B-Spline curve.
If you have an MDL background, then we believe that ConstructVertexList()
is a wrapper around the MDL function mdlElmdscr_stroke()
.
Here's a suggestion from Gerald Hernandez, a frequent contributor to the
Bentley Discussion Groups
on how to use ConstructVertexList()
to convert an Arc to a Line String …
Function StrokeArc(ByVal oArc As ArcElement, ByVal tolerance as Double) As LineElement Dim strokePoints() as Point3d strokePoints = oArc.ConstructVertexList (tolerance)' Create a Line String using the original Arc as a template.
' The new Line String inherits the properties and symbology of the Arc
Set StrokeArc= CreateLineElement1(oArc, strokePoints) Erase strokePoints End Function
The tolerance
argument tells the function how closely the array of points should match the original element.
The finer the tolerance, the closer the result is to the original.
When stroking an Arc, for example, you might set the tolerance to
some fraction of the Arc's radius.
Q How do I record a VBA macro?
A You can record a VBA macro from the VBA Projects dialog.
Open the VBA Projects dialog from the MicroStation menu Utilities|Macro|Project Manager. Select a project to make the Record button active, then perform a few operations using MicroStation's normal commands. Press the Stop button when you want to finish recording, and click the Edit button. You may have to hunt through the project file in the editor to find the macro you just recorded. VBA assigns an arbitrary name to your macro, and if you record several it's easy to become confused.
Hint: start the VBA editor, then rename your macro to something memorable as soon as you press the Stop button.
Q How do I use the Scroll Wheel on my mouse in the VBA IDE?
A VBA is showing its age: the Microsoft code base predates the arrival of mice having a scroll wheel.
The problem lies firmly in Microsoft's court. Fortunately, they have come up with a solution. Visit this Microsoft link to find how to enable the Scroll Wheel in the VBA IDE.
Q How do I use pointers in VB?
A Sometimes you just have to do those C things in VB. Here are some ideas from the Code Project.
Post questions about MicroStation programming to the MicroStation Programming Forum.