Publish Date: March 2006
In previous editions of BDNzine, we have explored developing AddIn applications in C++ and C#. In this article, we will look at how to implement the same basic application in VB.NET. Before proceeding, you need to have two important prerequisites -- MicroStation V8 XM Edition and Visual Studio .NET 2003 Edition. We will also be using some MKI files to add the rules to build VB.NET AddIns.
The example application in this article will scan the DGN file and list the element types that are present. Step one is to set up the environment. As of the writing of this article, the rules to build VB.NET AddIns are not in the delivery, so they have to be added. The base for these files are the C# versions included with the MicroStation SDK. The first one is LINKVBNETADDIN.MKI. This sets up the post link command to validate the AddIn and subsequently calls MKVBNET.MKI, which allows you to do the actual build, although some macros need to be set up before you proceed. You need to set what is being built -- a DLL, an EXE, or a module. In this example, we are building a DLL, so we need to set ASSEMBLY_DLL. Next, we need to set the name of the assembly that is being built and the files used to build the application as well as their dependencies. Other information that is set includes the company name, copyright, version, title and other similar metadata. The next items set in MKVBNET.MKI are the compiler and assembly linker macros. Finally, after all the macros are in place, the application can be compiled. The other set of rules that need to be added to the delivery determine how to append multiple reference assemblies for the application. This is done using the ASSEMBLY_REFERENCE macro. This macro is used in VBREFAPND.MKI, which allows our make file to add the necessary referenced assemblies. All of this backend infrastructure is leveraged in the application's make file.
Now we will look at the application development process. To start the application, use the Visual Studio .NET wizard to create a blank project and then add a DLL to the project. In this case, use the Visual Basic tab to set these in place. Next, add a blank form to the application and on this form put a list box that has the elements listed on it. For the dialog, you need a method to scan the file that will then build the list and a method to open the dialog and attach it to the MicroStation window system. Use the COM object model to do the scan and for the dialog, use MicroStation's window manager methods.
Imports Bentley.MicroStation.Winforms
Imports Bentley.Interop.MicroStationDGN
Imports Bentley.MicroStation
Imports Bentley.Windowing
Imports System.Windows.Forms
Namespace ProjectReviewApp
Public Class ProjectReviewForm
Inherits Bentley.MicroStation.WinForms.Adapter
Private Shared s_App As Bentley.Interop.MicroStationDGN.Application
Private Shared s_Current As ProjectReviewForm
Dim m_window As Bentley.Windowing.WindowContent
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
s_Current = Me
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
s_Current = Nothing
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents ListBox1 As System.Windows.Forms.ListBox
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.ListBox1 = New System.Windows.Forms.ListBox
Me.SuspendLayout()
'
'ListBox1
'
Me.ListBox1.Location = New System.Drawing.Point(48, 40)
Me.ListBox1.Name = "ListBox1"
Me.ListBox1.Size = New System.Drawing.Size(200, 173)
Me.ListBox1.TabIndex = 0
'
'ProjectReviewForm
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 268)
Me.Controls.Add(Me.ListBox1)
Me.Name = "ProjectReviewForm"
Me.Text = "ProjectReviewForm"
Me.ResumeLayout(False)
End Sub
#End Region
Public Function ScanFile() As Integer
Dim oEnum As Bentley.Interop.MicroStationDGN.ElementEnumerator
Dim oScanCriteria As Bentley.Interop.MicroStationDGN.ElementScanCriteriaClass
Dim iStatus As Integer
oScanCriteria = New Bentley.Interop.MicroStationDGN.ElementScanCriteriaClass
oEnum = Bentley.MicroStation.InteropServices.Utilities.ComApp.ActiveModelReference.Scan(oScanCriteria)
ListBox1.Items.Clear()
Do While oEnum.MoveNext
If ListBox1.Items.Contains(oEnum.Current.Type.ToString) = False Then
iStatus = ListBox1.Items.Add(oEnum.Current.Type.ToString)
End If
Loop
ScanFile = iStatus
End Function
Public Sub ShowForm()
If s_Current Is Nothing Then
s_Current = New ProjectReviewForm
End If
Dim winManager As Bentley.Windowing.WindowManager
winManager = Bentley.Windowing.WindowManager.GetForMicroStation
m_window = winManager.DockPanel(s_Current, "ProjectReviewForm", s_Current.Text, Bentley.Windowing.DockLocation.Floating)
End Sub
Public Sub CloseForm()
If s_Current Is Nothing Then
Exit Sub
End If
ProjectReviewAppVB.ReleaseDialog()
m_window.Close()
m_window = Nothing
s_Current = Nothing
End Sub
End Class
End Namespace
To build the "application" part, the class needs to inherit from the Bentley.MicroStation.Addin class. It also needs some metadata that describes the file defining the key-ins and the mdlTaskId that makes it known internally to MicroStation. In the constructor, the application calls its parent and passes the mdlDescriptor. There are also functions for handling the interaction with the dialog. The class must override the run method that is used as the entry point for the application. Next, another class is added to the application to implement the key-in entry points. This class will have the shared methods that connect the key-ins to the application.
Imports Bentley.MicroStation.WinForms
Imports Bentley.MicroStation.InteropServices
Imports Bentley.Interop.MicroStationDGN
Imports System.Runtime.InteropServices
Imports Bentley.MicroStation
Namespace ProjectReviewApp
<Bentley.MicroStation.AddInAttribute(keyinTree:="ProjectReviewAppVB.keyins", MdlTaskId:="ProjReviewVB")> _
Public Class ProjectReviewAppVB
Inherits Bentley.MicroStation.AddIn
Private Shared s_App As ProjectReviewAppVB
Private Shared pReviewDialog As ProjectReviewForm
Sub New(ByVal mdlDesc As System.IntPtr)
MyBase.New(mdlDesc)
s_App = Me
End Sub
Public Shared Function GetApp() As ProjectReviewAppVB
GetApp = s_App
End Function
Public Shared Function GetDialog() As ProjectReviewForm
If pReviewDialog Is Nothing Then
pReviewDialog = New ProjectReviewForm
End If
GetDialog = pReviewDialog
End Function
Protected Overrides Function run(ByVal cmdLine() As String) As Integer
run = 0
End Function
Public Shared Sub ReleaseDialog()
pReviewDialog = Nothing
End Sub
End Class
Public Class keyinCommands
Public Shared Sub Open(ByVal unparsed As String)
Dim pDialog As ProjectReviewForm
pDialog = ProjectReviewAppVB.GetDialog
If Not pDialog Is Nothing Then
pDialog.ScanFile()
pDialog.ShowForm()
End If
End Sub
Public Shared Sub Close(ByVal unparsed As String)
Dim pDialog As ProjectReviewForm
pDialog = ProjectReviewAppVB.GetDialog
If Not pDialog Is Nothing Then
pDialog.CloseForm()
End If
End Sub
Public Shared Sub Scan(ByVal unparsed As String)
Dim pDialog As ProjectReviewForm
pDialog = ProjectReviewAppVB.GetDialog
If pDialog Is Nothing Then
pDialog.ShowForm()
Else
pDialog.ScanFile()
End If
End Sub
End Class
End Namespace
The key-ins themselves are defined in a separate XML ProjectReviewAppVB.keyins file:
<?xml version="1.0" encoding="utf-8" ?>
<keyinTree xmlns="http://www.bentley.com/schemas/1.0/MicroStation/AddIn/keyinTree.xsd">
<RootkeyinTable ID="root">
<Keyword SubtableRef="ProjectReviewAppVBID" CommandClass="MacroCommand" CommandWord="ProjectReviewAppVB" />
</RootkeyinTable>
<SubkeyinTables>
<keyinTable ID="ProjectReviewAppVBID">
<Keyword SubtableRef="DialogID" CommandWord="DIALOG" />
<Keyword SubtableRef="ScanID" CommandWord="Scan" />
</keyinTable>
<keyinTable ID="DialogID">
<Keyword CommandWord="OPEN" />
<Keyword CommandWord="CLOSE" />
</keyinTable>
<keyinTable ID="ScanID">
<Keyword CommandWord="FILE" />
</keyinTable>
</SubkeyinTables>
<keyinHandlers>
<keyinHandler keyin="ProjectReviewAppVB DIALOG OPEN" Function="ProjectReviewApp.keyinCommands.Open"/>
<keyinHandler keyin="ProjectReviewAppVB DIALOG CLOSE" Function="ProjectReviewApp.keyinCommands.Close"/>
<keyinHandler keyin="ProjectReviewAppVB SCAN FILE" Function="ProjectReviewApp.keyinCommands.Scan"/>
</keyinHandlers>
</keyinTree>
This small XML file will be imported into the assembly that is created and used to insert the key-in commands into MicroStation's command table.
Once the application code is in place comes the process of putting it all together. In keeping with current Bentley standards, the application is built using a make file. In the make file, the macros are assigned and the source is built. One application file is copied into this project for the assembly information and the entire assembly is copied to the ..\mdlapp\ProjectReviewAppVB\Bin folder. The MKI files VBREFAPND.MKI and LINKVBNETADDIN.MKI are not in the standard delivery and are delivered with the sample code. These allow the make process to compile the VB source code and correctly process the assembly for use with MicroStation.
#----------------------------------------------------------------------
#
# $Copyright: (c) 2006 Bentley Systems, Incorporated. All rights reserved.$
#
# Application Make File
#
# Limited permission is hereby granted to reproduce and modify this
# copyrighted material provided that the resulting code is used only
# in conjunction with Bentley Systems' products under the terms of the
# license agreement provided therein, and that this notice is retained
# in its entirety in any such reproduction or modification.
#
#----------------------------------------------------------------------
appName = ProjectReviewAppVB
baseDir = $(_MakeFilePath)
%include mdl.mki
o = $(mdlapps)$(appName)/
ASSEMBLY_TARGET_DIRECTORY = $(o)bin/
MakeOutputDirectories:
~mkdir $(o)
~mkdir $(ASSEMBLY_TARGET_DIRECTORY)
#-----------------------------------------------------------------------
# Add references
#-----------------------------------------------------------------------
ASSEMBLY_REFERENCE = $(MS)/ustation.dll
%include vbrefapnd.mki
ASSEMBLY_REFERENCE = $(MS)/Assemblies/Bentley.MicroStation.dll
%include vbrefapnd.mki
ASSEMBLY_REFERENCE = $(MS)/Assemblies/Bentley.Windowing.dll
%include vbrefapnd.mki
ASSEMBLY_REFERENCE = $(MS)/Assemblies/Bentley.MicroStation.Interfaces.1.0.dll
%include vbrefapnd.mki
ASSEMBLY_REFERENCE = $(MS)/Assemblies/ECFramework/Bentley.General.1.0.dll
%include vbrefapnd.mki
ASSEMBLY_REFERENCE = $(MS)/Assemblies/Bentley.Interop.MicroStationDGN.dll
%include vbrefapnd.mki
ASSEMBLY_REFERENCE = C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/System.dll
%include vbrefapnd.mki
ASSEMBLY_REFERENCE = C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/System.Drawing.dll
%include vbrefapnd.mki
ASSEMBLY_REFERENCE = C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/System.Windows.Forms.dll
%include vbrefapnd.mki
ASSEMBLY_NAME = $(appName)
ASSEMBLY_DLL = 1
ASSEMBLY_DESCRIPTION = Example AddIn Implementing a MicroStation tool
ASSEMBLY_COMPANY_NAME = Bentley Systems, Incorporated
ASSEMBLY_COPYRIGHT = Copyright (c) 2006 Bentley Systems, Incorporated. All rights reserved.
ASSEMBLY_PRODUCT_NAME = MicroStation Sample Code
ASSEMBLY_TITLE=$(ASSEMBLY_NAME)
ASSEMBLY_VERSION=1.0.0.1
ASSEMBLY_FILE_VERSION=1.0.0.1
#ASSEMBLY_STRONGNAME = 1
ASSEMBLY_MODULE=AssemblyInfo.vb
ASSEMBLY_RES_TO_ADD_DIRECTORY = $(baseDir)
ASSEMBLY_RES_TO_ADD_FILENAME = $(appName).keyins
ASSEMBLY_SOURCE_LIST = $(baseDir)ProjectReviewAppVB.vb $(baseDir)ProjectReviewForm.vb $(baseDir)AssemblyInfo.vb
%include AssemblyDeflateResourceAppend.mki
%include LinkVBNetAddIn.mki
#this will write a cfg file that will append the application bin directory to the mdlapps cfg var.
$(MS)/Config/appl/$(appName)ProjectReviewAppVB.cfg : $(_MakeFileSpec)
>$@
\#
\# If this is placed into $$(MS)/Config/appl then it should
\# be possible to do "mdl load" on this sample AddIn.
\#
MS_ADDINPATH > $$(MS)mdlapps\/ProjectReviewAppVB\/bin\/
<
~time
This article and example demonstrate that the language used to implement an application is becoming less and less a limiting factor in application development.