AddIn Development Using VB.NET


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.