How to migrate from VB6 to VB .NET (wiring events)


This document was published with and applies to ArcGIS 9.3.1.
Summary To successfully convert Visual Basic 6 (VB6) code to Visual Basic .NET (VB .NET) requires modifications. There is not a completely automated, error free way to upgrade from VB6 to VB .NET. This topic is one example of how this conversion process might work. The original VB6 project has the functionality of dynamically wiring up events to show the number of selected features in the active view of ArcMap in a custom Windows form dialog box. Additionally, the ArcMap command that is used to open the Windows form contains an image.

This topic focuses on a migrating a moderately complicated ArcMap command from VB6 to VB .NET. Subjects, such as handling the command's image, interacting with a user created Windows form, and wiring up events is discussed as you migrate from VB6 to VB .NET.

Emphasis is on the mechanics of the conversion process, creating a functionally equivalent VB .NET project from the original VB6 version, improving the VB .NET project to take advantage of .NET coding best practices, and using the ESRI base class features available in the ESRI Visual Studio Integration tools to provide an alternative method for the conversion.

Development licensing Deployment licensing
ArcView ArcView
ArcEditor ArcEditor
ArcInfo ArcInfo

Additional Requirements
  • Visual Basic 6
  • Visual Basic 2008

In this topic


Obtaining the supporting data

This topic shows how to convert a customized ArcMap command that opens a Windows form from VB6 to VB .NET. To follow the steps in this topic, you need the required files. To get the files, see Migrating from Visual Basic 6 to Visual Basic 2008, Case Study #2 – Convert an intermediate level ArcMap command. Unzip the CaseStudy2.zip file onto your hard drive (for example, C:\CaseStudy2).
 
The following are the .zip files that are included in CaseStudy2.zip. Unzip each file to get the supporting data:

Testing the VB6 project

Do the following steps to test the VB6 project:
  1. In VB6, open the <your installation location>\CaseStudy2\Events\VB6\Project1.vbp file to load the project. Review the project's contents to become familiar with the project's purpose.
  2. Start ArcMap to test the VB6 .dll.
  3. Click the Tools menu and choose Customize. The Customize dialog box appears.
  4. Click the Add from file button and navigate to the <your installation location>\CaseStudy2\Events\VB6\Project1.dll file.
  5. Select the Project1.dll file and click Open. When the Customize dialog refreshes, click  the Commands tab, then scroll down and click the Developer Samples in the Categories section.
  6. Click and drag the Events VB6 command onto the ArcMap graphical user interface (GUI).
  7. In ArcMap, add layers from the sample data in the .zip file. If you add more than one layer, right-click the first layer in the table of contents (TOC), then choose Selection, Make This The Only Selectable Layer.
  8. Click the Events VB6 command (shows an image of the letter "e") on the ArcMap GUI. Form1 appears.
  9. Click the Wire Up the Map's SelectionChanged Event button on Form1.
  10. Click the Select Features tool and select some features on the first layer. The count of the number of selected features shows on Form1.

Performing the raw conversion from VB6 to VB .NET

Do the following steps for the raw conversion:
  1. Start Visual Studio 2008 (VB2008).
  2. Click the File menu, click Open, then click Convert. The Convert dialog box appears.
  3. On the Convert dialog box, choose the Visual Basic 2008 Upgrade Wizard and click OK.
  4. Click Next on the Visual Basic Upgrade Wizard Page 1 of 6.
  5. Click the Browse button on the Visual Basic Upgrade Wizard Page 2 of 6, select the file <your installation location>\CaseStudy2\Events\VB6\Project1.vbp, then click Next.
  6. Click Next on the Visual Basic Upgrade Wizard Page 3 of 6.
  7. Click Browse on the Visual Basic Upgrade Wizard Page 4 of 6 and specify the folder <your installation location>\CaseyStudy2\Events\VB2008_UpgradeRaw, then click Next.
  8. Click Next on the Visual Basic Upgrade Wizard Page 5 of 6, then wait while the conversion completes.

Creating a VB .NET functional equivalent project

Do the following steps to create a functional project:
  1. Create a copy of the <your installation location>\CaseStudy2\Events\VB2008_UpgradeRaw folder, then create another folder to perform the edits. In this case, create <your installation location>\CaseStudy2\Events\VB2008_Equivalency.
  2. Open the <your installation location>\CaseStudy2\Events\VB2008_Equivalency\Project1.sln project.
  3. Click the Build menu and choose Build Solution. The VB2008 project that generates will not compile. The project has five errors and one warning that must be corrected to have equivalent functionality.
  4. To correct these errors and test for equivalent functionality, do the following to the <your installation location>\CaseStudy2\Events\VB2008_Equivalency\Project1.sln project:
    1. The upgraded project uses the same names for the new VB2008 project as the VB6 project; therefore, make modifications so both versions of the .dll can be run side-by-side.

      See the following clsEvents.vb code example that shows what to change from and what to change to:

[VB.NET]
' Change the following from:
Private ReadOnly Property ICommand_Name() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Name
Get
ICommand_Name = "Events VB6"
End Get
End Property

Private ReadOnly Property ICommand_Caption() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Caption
Get
ICommand_Caption = "Events VB6"
End Get
End Property

' Change to:
Private ReadOnly Property ICommand_Name() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Name
Get
ICommand_Name = "Events VB2008"
End Get
End Property

Private ReadOnly Property ICommand_Caption() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Caption
Get
ICommand_Caption = "Events VB2008"
End Get
End Property
  1. The ICommand_HelpFile property expects a return argument.

    See the following clsEvents.vb code example that shows what to change from and what to change to:

[VB.NET]
' Change the following from:
Private ReadOnly Property ICommand_HelpFile() As String Implements ESRI.ArcGIS.SystemUI.ICommand.HelpFile
Get

End Get
End Property

' Change to:
Private ReadOnly Property ICommand_HelpFile() As String Implements ESRI.ArcGIS.SystemUI.ICommand.HelpFile
Get
Return Nothing
End Get
End Property
  1. To open the Windows form, frmResources, and set its application property, as well as show an image of the letter "e" on the command in ArcMap, use three Member (that is, Global) variables. Below the class clsEvents declaration, add the following code example to the clsEvents file:

[VB.NET]
'Member variables.
Private m_frmResources As New frmResources
Private m_hBitmap As IntPtr
Private m_application As ESRI.ArcGIS.Framework.IApplication
  1. VB6 shows images for commands in ArcMap different than in VB .NET. VB .NET does not use Windows handles (also known as, hWnd) like VB6. Also, memory for the bitmap image used on the ArcMap command must be released via a Windows application programming interface (API) call. Later in this topic, a better way to use images on ArcMap commands will be discussed. For now, follow the same programming paradigm in VB .NET as in VB 6 using the following code example, which shows what to change from and what to change to in the clsEvents.vb file:

[VB.NET]
' Change the following from:
Private ReadOnly Property ICommand_Bitmap() As ESRI.ArcGIS.esriSystem.OLE_HANDLE Implements ESRI.ArcGIS.SystemUI.ICommand.Bitmap
Get
'UPGRADE_WARNING: Lower bound of collection frmResources.ImageList1.ListImages has changed from 1 to 0. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="A3B628A0-A810-4AE2-BFA2-9E7A29EB9AD0"'
'UPGRADE_ISSUE: Picture property ImageList1.ListImages.Picture.Handle was not upgraded. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="CC4C7EC0-C903-48FC-ACCC-81861D12DA4A"'
ICommand_Bitmap = frmResources.ImageList1.Images.Item(1).Handle
End Get
End Property

' Change to:
Private ReadOnly Property ICommand_Bitmap() As System.Int32 Implements ESRI.ArcGIS.SystemUI.ICommand.Bitmap
Get

'Get the bitmap from ImageList on the WinForm.
Dim imageList As ImageList = m_frmResources.ImageList1
Dim imageCollection As ImageList.ImageCollection = imageList.Images
Dim image As Image = imageCollection.Item(0)
Dim bitmap As Bitmap = CType(image, Bitmap)
bitmap.MakeTransparent(bitmap.GetPixel(0, 0))

'Get the Windows handle on the bitmap. This requires releasing it manually.
m_hBitmap = bitmap.GetHbitmap()

'Return the integer version of the Windows handle.
Return CInt(m_hBitmap)

End Get
End Property

'Releasing the Windows handles documentation: http://msdn2.microsoft.com/en-us/library/1dz311e4(VS.80).aspx.
'Define the Windows gdi32.dll API call.
<Runtime.InteropServices.DllImport("gdi32.dll")> _
                                   Private Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean
End Function

Protected Overrides Sub Finalize()

'Release the memory for the bitmap associated with the command.
If (m_hBitmap.ToInt32() <> 0) Then
    DeleteObject(m_hBitmap)
End If
MyBase.Finalize()

End Sub
The image used on the Events VB2008 command in ArcMap is obtained from an ImageList of the Windows form, frmResources. As part of the Events VB2008 functionality, frmResources is never shown; its purpose is to house the events.bmp file that is used as the image letter "e" for the Events VB2008 command.
  1. In the VB6 version of the Sub ICommand_OnCreate, the frmEvents.Application property was set to the hook object. Because Windows forms are instantiated differently in VB .NET, delay setting the frmEvents.Application property until the Sub ICommand_OnClick. Instead, set the m_application Member variable and use it later. Change the clsEvents.vb file as shown in the following code example, which shows what to change from and what to change to:

[VB.NET]
' Change the following from:

Private Sub ICommand_OnCreate(ByVal hook As Object) Implements ESRI.ArcGIS.SystemUI.ICommand.OnCreate
    'UPGRADE_WARNING: Couldn't resolve default property of object hook. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="6A50421D-15FE-4896-8A1B-2EC21E9037B2"'
    frmEvents.Application = hook
End Sub

' Change to:

Private Sub ICommand_OnCreate(ByVal hook As Object) Implements ESRI.ArcGIS.SystemUI.ICommand.OnCreate

    'Set the ArcMap application hook.
    m_application = CType(hook, ESRI.ArcGIS.Framework.IApplication)

End Sub
  1. Because Windows forms are instantiated and used differently in VB6 than in VB .NET, make a code change to the Sub ICommand_OnClick. Notice how the setting of the frmEvents.Application property is now done in this Sub, rather than the Sub ICommand_OnCreate. Change the clsEvents.vb file as shown in the following code example, which shows what to change from and what to change to:

[VB.NET]
' Change the following from:

Private Sub ICommand_OnClick() Implements ESRI.ArcGIS.SystemUI.ICommand.OnClick
    frmEvents.Show()
End Sub

' Change to:

Private Sub ICommand_OnClick() Implements ESRI.ArcGIS.SystemUI.ICommand.OnClick

    'Open the Windows form that demonstrated the wiring of events.
    Dim frmEvents As New frmEvents
    frmEvents.Application = m_application
    frmEvents.Show()

End Sub
The preceding code example fixes the compile errors. Since the clsEvents.vb file had major changes, errors can occur. The following code example shows the complete clsEvents.vb file for your reference:
 

[VB.NET]
Option Strict Off
Option Explicit On
<System.Runtime.InteropServices.ProgId("clsEvents_NET.clsEvents")> Public Class clsEvents
    Implements ESRI.ArcGIS.SystemUI.ICommand

    'Member variables.
    Private m_frmResources As New frmResources
    Private m_hBitmap As IntPtr
    Private m_application As ESRI.ArcGIS.Framework.IApplication

    Private ReadOnly Property ICommand_Enabled() As Boolean Implements ESRI.ArcGIS.SystemUI.ICommand.Enabled
    Get
    ICommand_Enabled = True
    End Get
End Property

Private ReadOnly Property ICommand_Checked() As Boolean Implements ESRI.ArcGIS.SystemUI.ICommand.Checked
Get
ICommand_Checked = False
End Get
End Property

Private ReadOnly Property ICommand_Name() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Name
Get
ICommand_Name = "Events VB2008"
End Get
End Property

Private ReadOnly Property ICommand_Caption() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Caption
Get
ICommand_Caption = "Events VB2008"
End Get
End Property

Private ReadOnly Property ICommand_Tooltip() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Tooltip
Get
ICommand_Tooltip = ""
End Get
End Property

Private ReadOnly Property ICommand_Message() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Message
Get
ICommand_Message = ""
End Get
End Property

Private ReadOnly Property ICommand_HelpFile() As String Implements ESRI.ArcGIS.SystemUI.ICommand.HelpFile
Get
Return Nothing
End Get
End Property

Private ReadOnly Property ICommand_HelpContextID() As Integer Implements ESRI.ArcGIS.SystemUI.ICommand.HelpContextID
Get

End Get
End Property

Private ReadOnly Property ICommand_Bitmap() As System.Int32 Implements ESRI.ArcGIS.SystemUI.ICommand.Bitmap
Get

'Get the bitmap from ImageList on the WinForm.
Dim imageList As ImageList = m_frmResources.ImageList1
Dim imageCollection As ImageList.ImageCollection = imageList.Images
Dim image As Image = imageCollection.Item(0)
Dim bitmap As Bitmap = CType(image, Bitmap)
bitmap.MakeTransparent(bitmap.GetPixel(0, 0))

'Get the Windows handle on the bitmap. This requires releasing it manually.
m_hBitmap = bitmap.GetHbitmap()

'Return the integer version of the Windows handle.
Return CInt(m_hBitmap)

End Get
End Property

'Releasing the Windows handle documentation: http://msdn2.microsoft.com/en-us/library/1dz311e4(VS.80).aspx
'Define the Windows gdi32.dll API call.
<Runtime.InteropServices.DllImport("gdi32.dll")> _
                                   Private Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean
End Function

Protected Overrides Sub Finalize()

'Release the memory for the bitmap associated with the command.
If (m_hBitmap.ToInt32() <> 0) Then
    DeleteObject(m_hBitmap)
End If
MyBase.Finalize()

End Sub

Private ReadOnly Property ICommand_Category() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Category
Get
ICommand_Category = "Developer Samples"
End Get
End Property

Private Sub ICommand_OnCreate(ByVal hook As Object) Implements ESRI.ArcGIS.SystemUI.ICommand.OnCreate

    'Set the ArcMap application hook.
    m_application = CType(hook, ESRI.ArcGIS.Framework.IApplication)

End Sub

Private Sub ICommand_OnClick() Implements ESRI.ArcGIS.SystemUI.ICommand.OnClick

    'Openthe Windows form that demonstrated the wiring of events.
    Dim frmEvents As New frmEvents
    frmEvents.Application = m_application
    frmEvents.Show()

End Sub

End Class

Changing the project's properties

Do the following steps to change the project's properties and create a .dll and .tlb file name that matches what the customization does:
  1. Click the Project menu and choose Project1 properties.
  2. Click the Application tab and change the Assembly name from Project1 to Events.
  3. Change the Root namespace from Project1 to Events. When the project compiles, the Events.dll and Events.tlb files are created.
  4. Click the Debug tab and specify the start external program to be C:\Program Files\ArcGIS\Bin\ArcMap.exe. If you selected a different install directory for ArcMap, modify this path accordingly.
  5. Click the Compile tab and select the Register for COM Interop check box.
  6. When the upgrade wizard was used, extraneous references were added to the project. By reviewing the references in the VB6 project, you can determine that the following references can be eliminated from the VB2008 project. Select the following extraneous references in the Solution Explorer and remove them from project: 
  7. Click the Start Debugging button to test the project for functional equivalency to VB6.

Testing the VB2008 project

Do the following steps to test the VB2008 project:
  1. Start ArcMap.
  2. Click the Tools menu and choose Customize. The Customize dialog box appears.
  3. Click the Add from file button and navigate to the <your installation location>\CaseStudy2\Events\VB2008_Equivalency\bin folder.
  4. Select the Events.tlb file.
  5. Click Open. Unlike the VB6 project where you selected the .dll file, choose the .tlb file.
  6. When the Customize dialog box refreshes, click the Commands tab, scroll down, then click the Developer Samples in the Categories section.
  7. Click, then drag the Events VB2008 command onto the ArcMap GUI. 

Improving the VB2008 project to conform to .NET standards

If necessary, make changes to the underlying code to conform to .NET coding standards. Create a copy of the <your installation location>\CaseStudy2\Events\VB2008_Equivalency folder and create a folder to perform the edits. In this case, the new folder is named <your installation location>\CaseStudy2\Events\VB2008_Equivalency2.
 
In <your installation location>\CaseStudy2\Events\VB2008_Equivalency2\Project1.sln project, use the following .NET standards:
  1. Set Option Strict to equal On to catch potential casting errors.
  2. Remove the letter "p" at the beginning of every variable name. Pointers are not used by .NET managed code.
  3. Declare and instantiate objects on the same line of code where possible to make the code more readable and eliminate variables that are unused.
  4. Do not declare and use an object until it is needed in the code; that is, do not declare all the variables at the top of each method (another way to eliminate variables that are never used).
  5. Use Imports statements to shorten the length of coding statements.
  6. Use Return statements instead of the function and property name for returning variables.
  7. Comment the code.
  8. Eliminate unused variables.
  9. Use Member (also known as, Global) variables judiciously.

[VB.NET]
Option Strict Off
Option Explicit On
<System.Runtime.InteropServices.ProgId("clsEvents_NET.clsEvents")> Public Class clsEvents
    Implements ESRI.ArcGIS.SystemUI.ICommand

    'Member variables.
    Private m_frmResources As New frmResources
    Private m_hBitmap As IntPtr
    Private m_application As ESRI.ArcGIS.Framework.IApplication

    Private ReadOnly Property ICommand_Enabled() As Boolean Implements ESRI.ArcGIS.SystemUI.ICommand.Enabled
    Get
    ICommand_Enabled = True
    End Get
End Property

Private ReadOnly Property ICommand_Checked() As Boolean Implements ESRI.ArcGIS.SystemUI.ICommand.Checked
Get
ICommand_Checked = False
End Get
End Property

Private ReadOnly Property ICommand_Name() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Name
Get
ICommand_Name = "Events VB2008"
End Get
End Property

Private ReadOnly Property ICommand_Caption() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Caption
Get
ICommand_Caption = "Events VB2008"
End Get
End Property

Private ReadOnly Property ICommand_Tooltip() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Tooltip
Get
ICommand_Tooltip = ""
End Get
End Property

Private ReadOnly Property ICommand_Message() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Message
Get
ICommand_Message = ""
End Get
End Property

Private ReadOnly Property ICommand_HelpFile() As String Implements ESRI.ArcGIS.SystemUI.ICommand.HelpFile
Get
Return Nothing
End Get
End Property

Private ReadOnly Property ICommand_HelpContextID() As Integer Implements ESRI.ArcGIS.SystemUI.ICommand.HelpContextID
Get

End Get
End Property

Private ReadOnly Property ICommand_Bitmap() As System.Int32 Implements ESRI.ArcGIS.SystemUI.ICommand.Bitmap
Get

'Get the bitmap from ImageList on the WinForm.
Dim imageList As ImageList = m_frmResources.ImageList1
Dim imageCollection As ImageList.ImageCollection = imageList.Images
Dim image As Image = imageCollection.Item(0)
Dim bitmap As Bitmap = CType(image, Bitmap)
bitmap.MakeTransparent(bitmap.GetPixel(0, 0))

'Get the Windows handle on the bitmap. This requires releasing it manually.
m_hBitmap = bitmap.GetHbitmap()

'Return the integer version of the Windows handle.
Return CInt(m_hBitmap)

End Get
End Property

'Releasing the Windows handles documentation: http://msdn2.microsoft.com/en-us/library/1dz311e4(VS.80).aspx
'Define the Windows gdi32.dll API call.
<Runtime.InteropServices.DllImport("gdi32.dll")> _
                                   Private Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean
End Function

Protected Overrides Sub Finalize()

'Release the memory for the bitmap associated with the command.
If (m_hBitmap.ToInt32() <> 0) Then
    DeleteObject(m_hBitmap)
End If
MyBase.Finalize()

End Sub

Private ReadOnly Property ICommand_Category() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Category
Get
ICommand_Category = "Developer Samples"
End Get
End Property

Private Sub ICommand_OnCreate(ByVal hook As Object) Implements ESRI.ArcGIS.SystemUI.ICommand.OnCreate

    'Set the ArcMap application hook.
    m_application = CType(hook, ESRI.ArcGIS.Framework.IApplication)

End Sub

Private Sub ICommand_OnClick() Implements ESRI.ArcGIS.SystemUI.ICommand.OnClick

    'The Windows form that demonstrated the wiring of events.
    Dim frmEvents As New frmEvents
    frmEvents.Application = m_application
    frmEvents.Show()

End Sub

End Class
 

[VB.NET]
Option Strict On
Option Explicit On
<System.Runtime.InteropServices.ProgId("clsEvents_NET.clsEvents")> Public Class clsEvents
    Implements ESRI.ArcGIS.SystemUI.ICommand

    'Member variables.
    Private m_frmResources As New frmResources
    Private m_hBitmap As IntPtr
    Private m_application As ESRI.ArcGIS.Framework.IApplication

    Private ReadOnly Property ICommand_Enabled() As Boolean Implements ESRI.ArcGIS.SystemUI.ICommand.Enabled
    Get
    Return True
    End Get
End Property

Private ReadOnly Property ICommand_Checked() As Boolean Implements ESRI.ArcGIS.SystemUI.ICommand.Checked
Get
Return False
End Get
End Property

Private ReadOnly Property ICommand_Name() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Name
Get
Return "Events VB2008 ver2"
End Get
End Property

Private ReadOnly Property ICommand_Caption() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Caption
Get
Return "Events VB2008 ver2"
End Get
End Property

Private ReadOnly Property ICommand_Tooltip() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Tooltip
Get
Return ""
End Get
End Property

Private ReadOnly Property ICommand_Message() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Message
Get
Return ""
End Get
End Property

Private ReadOnly Property ICommand_HelpFile() As String Implements ESRI.ArcGIS.SystemUI.ICommand.HelpFile
Get
Return Nothing
End Get
End Property

Private ReadOnly Property ICommand_HelpContextID() As Integer Implements ESRI.ArcGIS.SystemUI.ICommand.HelpContextID
Get
Return Nothing
End Get
End Property

Private ReadOnly Property ICommand_Bitmap() As System.Int32 Implements ESRI.ArcGIS.SystemUI.ICommand.Bitmap
Get

'Get the bitmap from ImageList on the WinForm.
Dim imageList As ImageList = m_frmResources.ImageList1
Dim imageCollection As ImageList.ImageCollection = imageList.Images
Dim image As Image = imageCollection.Item(0)
Dim bitmap As Bitmap = CType(image, Bitmap)
bitmap.MakeTransparent(bitmap.GetPixel(0, 0))

'Get the Windows handle on the bitmap. This requires releasing it manually.
m_hBitmap = bitmap.GetHbitmap()

'Return the integer version of the Windows handle.
Return CInt(m_hBitmap)

End Get
End Property

'Releasing the Windows handles documentation: http://msdn2.microsoft.com/en-us/library/1dz311e4(VS.80).aspx
'Define the Windows gdi32.dll API call.
<Runtime.InteropServices.DllImport("gdi32.dll")> _
                                   Private Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean
End Function

Protected Overrides Sub Finalize()

'Release the memory for the bitmap associated with the command.
If (m_hBitmap.ToInt32() <> 0) Then
    DeleteObject(m_hBitmap)
End If
MyBase.Finalize()

End Sub

Private ReadOnly Property ICommand_Category() As String Implements ESRI.ArcGIS.SystemUI.ICommand.Category
Get
Return "Developer Samples"
End Get
End Property

Private Sub ICommand_OnCreate(ByVal hook As Object) Implements ESRI.ArcGIS.SystemUI.ICommand.OnCreate

    'Set the ArcMap application hook.
    m_application = CType(hook, ESRI.ArcGIS.Framework.IApplication)

End Sub

Private Sub ICommand_OnClick() Implements ESRI.ArcGIS.SystemUI.ICommand.OnClick

    'Open the Windows form that demonstrated the wiring of events.
    Dim frmEvents As New frmEvents
    frmEvents.Application = m_application
    frmEvents.Show()

End Sub

End Class

[VB.NET]
Option Strict Off
Option Explicit On
Friend Class frmEvents
Inherits System.Windows.Forms.Form
Dim m_pApp As ESRI.ArcGIS.Framework.IApplication
Private WithEvents m_pActiveViewEvents As ESRI.ArcGIS.Carto.Map

'Accessor function defined to fetch the application object from the OnCreate method in the COM class.
Public WriteOnly Property Application() As ESRI.ArcGIS.Framework.IApplication
Set(ByVal Value As ESRI.ArcGIS.Framework.IApplication)
m_pApp = Value
End Set
End Property


Private Sub m_pActiveViewEvents_SelectionChanged() Handles m_pActiveViewEvents.SelectionChanged

    Dim pMxDoc As ESRI.ArcGIS.ArcMapUI.IMxDocument
    pMxDoc = m_pApp.Document

    Dim contentsView As ESRI.ArcGIS.ArcMapUI.IContentsView
    contentsView = pMxDoc.contentsView(0)

    Dim featureLayer As ESRI.ArcGIS.Carto.IFeatureLayer
    featureLayer = contentsView.SelectedItem

    Dim tableSelection As ESRI.ArcGIS.Carto.ITableSelection
    tableSelection = featureLayer

    Dim selectionSet As ESRI.ArcGIS.Geodatabase.ISelectionSet
    selectionSet = tableSelection.selectionSet

    Text1.Text = CStr(selectionSet.Count)

End Sub

Private Sub Command1_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command1.Click
    Label1.Visible = True
    Label2.Visible = True
    Text1.Visible = True

    Dim pMxDoc As ESRI.ArcGIS.ArcMapUI.IMxDocument
    pMxDoc = m_pApp.Document
    m_pActiveViewEvents = pMxDoc.FocusMap
End Sub

Private Sub frmEvents_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load
    Label1.Visible = False
    Label2.Visible = False
    Text1.Visible = False
End Sub

End Class

[VB.NET]
Option Strict On
Option Explicit On

Imports ESRI.ArcGIS.Framework
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.ArcMapUI
Imports ESRI.ArcGIS.Geodatabase

Friend Class frmEvents
Inherits System.Windows.Forms.Form

'Member variables.
Dim m_application As IApplication

'The event handler.
Private WithEvents m_map_Events As Map

'Accessor function defined to fetch the application object from the OnCreate method in the COM class.
Public WriteOnly Property Application() As ESRI.ArcGIS.Framework.IApplication

Set(ByVal Value As IApplication)
m_application = Value
End Set

End Property

Private Sub m_pActiveViewEvents_SelectionChanged() Handles m_map_Events.SelectionChanged

    'Get the ArcMap document.
    Dim document As IDocument = m_application.Document

    'Cast to an IMxDocument.
    Dim mxDocument As IMxDocument = CType(document, IMxDocument)

    'Get the Display tab (item 0) in the TOC (also known as, the ContentsView).
    Dim contentsView As IContentsView = mxDocument.ContentsView(0)

    'Get the selected item in the TOC.
    Dim selectedItem As Object = contentsView.SelectedItem

    'Cast it to a feature layer.
    Dim featureLayer As IFeatureLayer = CType(selectedItem, IFeatureLayer)

    'Cast the feature layer to a table selection.
    Dim tableSelection As ITableSelection = CType(featureLayer, ITableSelection)

    'Get the selected set of records.
    Dim selectionSet As ISelectionSet = tableSelection.SelectionSet

    'Display the count of selected records.
    Text1.Text = CStr(selectionSet.Count)

End Sub

Private Sub Command1_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command1.Click

    'Make the controls visible when the button is clicked.
    Label1.Visible = True
    Label2.Visible = True
    Text1.Visible = True

    'Get the ArcMap document.
    Dim document As IDocument = m_application.Document

    'Cast to an IMxDocument.
    Dim mxDocument As IMxDocument = CType(document, IMxDocument)

    'Get the map.
    Dim map As IMap = mxDocument.FocusMap

    'Wire up the map's event handler.
    m_map_Events = CType(map, Map)

End Sub

Private Sub frmEvents_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load

    'Make the controls invisible on the form load.
    Label1.Visible = False
    Label2.Visible = False
    Text1.Visible = False

End Sub

End Class

Removing references

Extraneous references were removed from the project. Expand the references in the Solution Explorer and remove the following:
 
If you rebuild the project, an error message appears. Do the following to correct this error message:
  1. Open the project's properties.
  2. Click the References tab and scroll down to the Imported namespaces section.
  3. Clear the Microsoft.VisualBasic.Compatibility check box and save the project.
  4. Select the following files and folders to delete unnecessary files:
  5. Right-click the files and folders and choose Delete.
  6. Click the Start Debugging button to test the project in ArcMap.

Testing the VB2008 project

Do the following steps to test the VB2008 project:
  1. Start ArcMap. 
  2. Click the Tools menu and choose Customize. The Customize dialog box appears. 
  3. Click the Add from file button and navigate to the <your installation location>\CaseStudy2\Events\VB2008_Equivalency2\bin folder.
  4. Select the Events.tlb file.
  5. Click Open. Unlike the VB6 project where you selected the .dll file, choose the .tlb file.
  6. When the Customize dialog box refreshes, click the Commands tab, scroll down, then click the Developer Samples in the Categories section.
  7. Click, then drag the Events VB2008 ver2 command onto the ArcMap GUI. 

Using the ESRI base classes and porting prior code

You can choose to use the new ESRI programming paradigm; namely, using the base classes. See the following steps:
  1. Start Visual Studio 2008.
  2. Click the File menu and choose New Project. The New Project dialog box appears.
  3. Click to expand the Visual Basic, ArcGIS, and Desktop nodes.
  4. Select the Class Library (ArcMap) template. Name the template, Events2008, and click OK. The ArcGIS Project Wizard appears.
  5. On the ArcGIS Project Wizard, add the following assemblies to the project:
  6. Click Finish.
  7. Right-click the default Class1.vb file in the Solution Explorer and select Delete.
  8. Click the Project menu and choose Add New Item. The Add New Item dialog box appears.
  9. Click to expand the Common Items and ArcGIS nodes.
  10. Select the Base Command template. Name the template, clsEvents.vb, and click the Add button. The ArcGIS New Item Wizard Options dialog box appears.
  11. Choose Desktop ArcMap Command from the list box and click OK.
  12. Click Save. The <your installation location>\CaseStudy2\Events\Events2008\Events2008.sln file is created.
 
You now have the initial project based on the created ESRI base classes. Make the necessary modifications by doing the following steps: 
  1. Set the bitmap image for the clsEvents.vb ArcMap command. Unlike the VB6 project and the other VS2008 projects that pulled the command's bitmap from a ImageList control embedded in a Windows form that never shows, use the ESRI base classes mechanism to set an image for a command. Do this by performing the following steps:
    1. Right-click the clsEvents.bmp file in the Solution Explorer and choose Delete.
    2. Open Windows Explorer and copy the <your installation location>\CaseStudy2\Events\VB6\events.bmp file to the \CaseStudy2\Events\Events2008\Events2008 folder.
    3. In Windows Explorer, rename the <your installation location>\CaseStudy2\Events\Events2008\Events2008\events.bmp file to <your installation location>\CaseStudy2\Events\Events2008\Events2008\clsEvents.bmp.
    4. In the Events2008 VB2008 project, click the Project menu and choose Add Existing Item, then add the clsEvents.bmp file to the project.
    5. Right-click the clsEvents.bmp file in the Solution Explorer and choose Properties.
    6. Change the Build Action to Embedded Resource (ensures the new version of the bitmap is compiled as part of the project, so it displays on the ArcMap GUI).
  2. To make your command recognizable by ArcMap, define the base command properties. Change the public properties in the Public Sub New (also known as, the constructor) of the clsEvents.vb file. See the following code example:

[VB.NET]
MyBase.m_category = "Developer Samples" 'Localizable text.
MyBase.m_caption = "Events VB2008 via Base Class" 'Localizable text.
MyBase.m_message = "" 'Localizable text.
MyBase.m_toolTip = "" 'Localizable text.
MyBase.m_name = "Events2008_clsEvents" 'Unique ID, non-localizable (for example, "MyCategory_ArcMapCommand").
  1. At this point, the Sub OnClick in the clsEvents.vb file does not function. You want it to launch your Windows form that performs the wiring of events and show the number of selected features. Borrowing from the previous VB2008 project you created, modify the Sub OnClick in the clsEvents.vb file to the following code example:

[VB.NET]
Public Overrides Sub OnClick()

'Open the Windows form that demonstrated the wiring of events.
Dim frmEvents As New frmEvents
frmEvents.Application = m_application
frmEvents.Show()

End Sub
Since the clsEvents.vb file had major changes, errors can occur. The following code example shows the complete clsEvents.vb file for your reference:
 

[VB.NET]
Imports System.Runtime.InteropServices
Imports System.Drawing
Imports ESRI.ArcGIS.ADF.BaseClasses
Imports ESRI.ArcGIS.ADF.CATIDs
Imports ESRI.ArcGIS.Framework
Imports ESRI.ArcGIS.ArcMapUI

<ComClass(clsEvents.ClassId, clsEvents.InterfaceId, clsEvents.EventsId), _
          ProgId("Events2008.clsEvents")> _
          Public NotInheritable Class clsEvents
    Inherits BaseCommand

    #Region "COM GUIDs"
    ' These  GUIDs provide the COM identity for this class
    ' and its COM interfaces. If you change them, existing
    ' clients cannot access the class.
    Public Const ClassId As String = "c2fbde88-5dea-4ae9-86ed-ac63e8a15e77"
    Public Const InterfaceId As String = "851f15ab-1225-4d24-9117-90ba029202b0"
    Public Const EventsId As String = "6f4e6e8c-4986-4741-8a63-4815f1ad9a50"
    #End Region

    #Region "COM Registration Function(s)"
    <ComRegisterFunction(), ComVisibleAttribute(False)> _
                         Public Shared Sub RegisterFunction(ByVal registerType As Type)
        ' Required for ArcGIS Component Category Registrar support.
        ArcGISCategoryRegistration(registerType)

        'Add any COM registration code after the ArcGISCategoryRegistration() call.

    End Sub

    <ComUnregisterFunction(), ComVisibleAttribute(False)> _
                           Public Shared Sub UnregisterFunction(ByVal registerType As Type)
        ' Required for ArcGIS Component Category Registrar support.
        ArcGISCategoryUnregistration(registerType)

        'Add any COM unregistration code after the ArcGISCategoryUnregistration() call.

    End Sub

    #Region "ArcGIS Component Category Registrar generated code"
    Private Shared Sub ArcGISCategoryRegistration(ByVal registerType As Type)
    Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
    MxCommands.Register(regKey)

End Sub

Private Shared Sub ArcGISCategoryUnregistration(ByVal registerType As Type)
Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
MxCommands.Unregister(regKey)

End Sub

#End Region
#End Region

Private m_application As IApplication

' A creatable COM class must have a Public Sub New()
' with no parameters; otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.

Public Sub New()
    MyBase.New()

    ' TODO: Define values for the public properties.
    MyBase.m_category = "Developer Samples" 'Localizable text.
    MyBase.m_caption = "Events VB2008 via Base Class" 'Localizable text.
    MyBase.m_message = "" 'Localizable text.
    MyBase.m_toolTip = "" 'Localizable text.
    MyBase.m_name = "Events VB2008 via Base Class" 'Unique ID, non-localizable (for example, "MyCategory_ArcMapCommand").

    Try
    'TODO: Change bitmap name if necessary.
    Dim bitmapResourceName As String = Me.GetType().Name + ".bmp"
    MyBase.m_bitmap = New Bitmap(Me.GetType(), bitmapResourceName)
    Catch ex As Exception
    System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap")
    End Try

End Sub

Public Overrides Sub OnCreate(ByVal hook As Object)
If Not hook Is Nothing Then
    m_application = CType(hook, IApplication)

    'Disable if it is not ArcMap.
    If TypeOf hook Is IMxApplication Then
        MyBase.m_enabled = True
    Else
        MyBase.m_enabled = False
    End If
End If

' TODO:  Add other initialization code.
End Sub

Public Overrides Sub OnClick()

'Open the Windows form that demonstrated the wiring of events.
Dim frmEvents As New frmEvents
frmEvents.Application = m_application
frmEvents.Show()

End Sub

End Class
  1. Instead of recreating the work in the Windows form that performed the wiring of events and showed the number of selected features, borrow from the previous VB2008 project by doing the following steps:
    1. Open Windows Explorer and copy the frmEvents.Designer.vb, frmEvents.resx, and frmEvents.vb files in the <your installation location>\CaseStudy2\Events\VB2008_Equivalency2 folder to the \CaseyStudy2\Events\Events2008\Events2008 folder.
    2. In the Events2008 VB2008 project, click the Project menu and choose Add Existing Item. Add the frmEvents.Designer.vb, frmEvents.resx, and frmEvents.vb files to the project (image for the frmEvents.vb file in the Solution Explorer looks like a class file).
    3. In the Solution Explorer, add the System.Windows.Forms reference to the project (changes the frmEvents.vb image to look like a dialog box).
  2. To demonstrate that handling of events is different (and advocated by some to be superior) in VB2008 than in VB6, add another button to the frmEvents Windows form that allows for the dynamically un-wiring of the map's SelectionChanged event. You will also demonstrate how wiring of events in VB2008 can be done using the concept of a delegate by using the AddressOf, AddHandler, and RemoveHandler keywords. This is different than VB6 where you only use the WithEvents keyword. Do the following steps to accomplish this:
    1. In the visual designer of the frmEvents.vb file, copy the button on the form, then paste it at the bottom of the form (resize the form to be longer).
    2. Right-click the copied button and change the following properties:
      • (Name): btnUnwire
      • Text: UnWire Up the Map's SelectionChanged Event
    3. Double-click the added button to open the code editor with a new Click event stub.
    4. In the frmEvents.vb file, make the following code changes to the existing Member variable near the top of the class file. See the following code example that shows what to change from and what to change to:

[VB.NET]
'Change the following from:
'The event handler.
Private WithEvents m_map_Events As Map

'Change to:
'The event handler.
'IntelliSense will only get you so far in finding the IActiveViewEvents_Event
'interface. Manually add the _Event to the end of the
'interface you find for IActiveViewEvents. See the following topics for more
'information:
'ms-help://MS.VSCC.v90/MS.VSIPCC.v90/ESRI.EDNv9.3/NET_Engine/8dbe2ce3-f2cc-497e-8a6f-b89ab93d1373.htm
'ms-help://MS.VSCC.v90/MS.VSIPCC.v90/ESRI.EDNv9.3/NET_Engine/da846639-efbc-491d-801b-1cb9be557ec4.htm
Private m_map_Events As IActiveViewEvents_Event
  1. Change the Sub m_pActiveViewEvents_SelectionChanged signature in frmEvents.vb from and to the following code example:

[VB.NET]
'Change the following from:

Private Sub m_pActiveViewEvents_SelectionChanged() Handles m_map_Events.SelectionChanged

    'Change to:

    Private Sub OnActiveViewEventsSelectionChanged()
You are only changing the signature (that is, the first line) of the Sub, not the content in the Sub.
  1. Modify the Sub Command1_Click of the frmEvents.vb file to use the new mechanism for wiring up events. See the following code example that shows what to change from and what to change to:

[VB.NET]
'Change the following from:

Private Sub Command1_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command1.Click

    'Make the controls visible when the button is clicked.
    Label1.Visible = True
    Label2.Visible = True
    Text1.Visible = True

    'Get the ArcMap document.
    Dim document As IDocument = m_application.Document

    'Cast to an IMxDocument.
    Dim mxDocument As IMxDocument = CType(document, IMxDocument)

    'Wire up the map's event handler.
    m_map_Events = CType(mxDocument.FocusMap, Map)

End Sub


'Change to:

Private Sub Command1_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command1.Click

    'Make the controls visible when the button is clicked.
    Label1.Visible = True
    Label2.Visible = True
    Text1.Visible = True

    'Get the ArcMap document.
    Dim document As IDocument = m_application.Document

    'Cast to an IMxDocument.
    Dim mxDocument As IMxDocument = CType(document, IMxDocument)
    Dim map As ESRI.ArcGIS.Carto.IMap = mxDocument.FocusMap

    ' Set the map's IActiveView event handler.
    m_map_Events = CType(Map, ESRI.ArcGIS.Carto.IActiveViewEvents_Event)

    ' Create an instance of the delegate and add it to SelectionChanged event.
    AddHandler m_map_Events.SelectionChanged, AddressOf OnActiveViewEventsSelectionChanged

End Sub
  1. Add the capability to un-wire the map's SelectionChanged event. Do this by modifying the Sub btnUnWire_Click in the frmEvents.vb file. See the following code example:

[VB.NET]
Private Sub btnUnWire_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUnWire.Click

    'Remove the event handler. A nice feature compared to VB6.
    RemoveHandler m_map_Events.SelectionChanged, AddressOf OnActiveViewEventsSelectionChanged

End Sub
Since the frmEvents.vb file had major changes, errors can occur. The following code example shows the complete frmEvents.vb file for your reference:
 

[VB.NET]
Option Strict On
Option Explicit On

Imports ESRI.ArcGIS.Framework
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.ArcMapUI
Imports ESRI.ArcGIS.Geodatabase

Friend Class frmEvents
Inherits System.Windows.Forms.Form

'Member variables.
Dim m_application As IApplication

'The event handler.
'IntelliSense will only get you so far in finding the IActiveViewEvents_Event
'interface. Manually add the _Event to the end of the the
'interface you find for IActiveViewEvents. See the following ESRI topics for more
'information:
'ms-help://MS.VSCC.v90/MS.VSIPCC.v90/ESRI.EDNv9.3/NET_Engine/8dbe2ce3-f2cc-497e-8a6f-b89ab93d1373.htm
'ms-help://MS.VSCC.v90/MS.VSIPCC.v90/ESRI.EDNv9.3/NET_Engine/da846639-efbc-491d-801b-1cb9be557ec4.htm
Private m_map_Events As IActiveViewEvents_Event

'Accessor function defined to fetch the application object from the OnCreate method in the COM class.
Public WriteOnly Property Application() As ESRI.ArcGIS.Framework.IApplication

Set(ByVal Value As IApplication)
m_application = Value
End Set

End Property

Private Sub OnActiveViewEventsSelectionChanged()

    'Get the ArcMap document.
    Dim document As IDocument = m_application.Document

    'Cast to an IMxDocument.
    Dim mxDocument As IMxDocument = CType(document, IMxDocument)

    'Get the Display tab (item 0) in the TOC, also known as, the ContentsView.
    Dim contentsView As IContentsView = mxDocument.ContentsView(0)

    'Get the selected item in the TOC.
    Dim selectedItem As Object = contentsView.SelectedItem

    'Cast it to a feature layer.
    Dim featureLayer As IFeatureLayer = CType(selectedItem, IFeatureLayer)

    'Cast the feature layer to a table selection.
    Dim tableSelection As ITableSelection = CType(featureLayer, ITableSelection)

    'Get the selected set of records.
    Dim selectionSet As ISelectionSet = tableSelection.SelectionSet

    'Display the count of selected records.
    Text1.Text = CStr(selectionSet.Count)

End Sub

Private Sub Command1_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command1.Click

    'Make the controls visible when the button is clicked.
    Label1.Visible = True
    Label2.Visible = True
    Text1.Visible = True

    'Get the ArcMap document.
    Dim document As IDocument = m_application.Document

    'Cast to an IMxDocument.
    Dim mxDocument As IMxDocument = CType(document, IMxDocument)

    'Get the map.
    Dim map As IMap = mxDocument.FocusMap

    'Wire up the map's event handler.
    m_map_Events = CType(map, ESRI.ArcGIS.Carto.IActiveViewEvents_Event)

    ' Create an instance of the delegate and add it to SelectionChanged.
    AddHandler m_map_Events.SelectionChanged, AddressOf OnActiveViewEventsSelectionChanged

End Sub

Private Sub frmEvents_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load

    'Make the controls invisible on the form load.
    Label1.Visible = False
    Label2.Visible = False
    Text1.Visible = False

End Sub

Private Sub btnUnWire_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUnWire.Click

    'Remove the event handler. A nice feature compared to VB6.
    RemoveHandler m_map_Events.SelectionChanged, AddressOf OnActiveViewEventsSelectionChanged

End Sub

End Class
  1. Click the Start Debugging button to start ArcMap and test the functionality.
Because the COM references and component categories have been set via the code as part of the ESRI Base Command project template, it is not necessary to click the Add from file button on the Customize dialog box in ArcMap. The command named, Events VB2008 via Base Class, is automatically added to the Developer Sample category on the Customize dialog box.


See Also:

How to migrate from VB6 to VB .NET (copying table selection)
Migrating Visual Basic 6.0 code to Visual Studio .NET
Resources for upgrading Visual Basic 6.0 code to Visual Basic .NET
Common issues when migrating from Visual Basic 6.0 to Visual Basic .NET