This document was published with and applies to ArcGIS 9.3.
A 9.2 version also exists.
A 9.2 version also exists.
In this topic
- Dealing with issues before upgrading
- Dealing with issues after upgrading
- Required changes after upgrading
- Other common issues after upgrading
The following outlines how to deal with issues found by the Visual Basic (VB) 6.0 code advisor add-in when accessing your VB 6.0 code before upgrading:
- Declare '<variable>' with an early-bound data type—In most cases, it is advisable to declare variables with a specific data type, but this is not always possible. You may find this issue reported on any implemented ArcObjects interface member. For example, in a VB 6.0 class that implements the ICommand interface, you may find this error referring to the hook parameter of the ICommand.OnCreate method. This method is defined by the ArcObjects application programming interface (API) and uses a late-bound data type (because different data types might be passed here); it is not possible for you to change this declaration. However, you may want to add fault-tolerant code that checks the type of the parameter passed in.
- Unused library references—Before upgrading your VB 6.0 project, verify you have no unnecessary library or component references in your project as this can slow down the upgrade process—interop assemblies will automatically generate for these references whether they are required or not.
The following outlines how to deal with issues found by the Visual Basic Upgrade wizard after upgrading. The Visual Basic Upgrade wizard cannot automate 100 percent of the necessary code changes when migrating from VB 6.0. In some cases, no direct equivalent for the VB 6.0 code may be available. In other cases, you may need to make manual changes to take advantage of the new features available in Visual Basic .NET (VB.NET).
The upgrade wizard also adds comments in your code to highlight the issues listed in the upgrade report. Press Ctrl+Alt+K to open the Task List and double-click an issue to go to that line of code. By default, only the upgrade error issues are listed in the Task List. To also display all upgrade warning issues (those that may not actually cause a compilation error), click Tools, Options, Environment, then Task List and add UPGRADE_WARNING to the displayed token list.
Before you go through the upgrade report of your new .NET project, review the following list of commonly encountered issues:
- Compile Error - '<interface>__<member>' cannot implement '<member>' because there is no matching property on interface '<interface>'—You can encounter this compile error, for example, after upgrading a project that includes a class implementing ICommand. The type of ICommand.Bitmap property in the esriSystemUI object library is esriSystem.OLE_HANDLE. However, the type of ICommand.Bitmap property in the ESRI.ArcGIS.SystemUI .NET assembly is Integer, more specifically an integer pointer to a bitmap. Solve this compile error by changing the return type of ICommand_Bitmap to Integer. See the following code example:
Private ReadOnly Property ICommand_Bitmap() As Integer Implements ICommand.Bitmap
Other examples of where you can encounter this error are the members ITool.Cursor, IToolControl.hWnd, and IDockableWindowDef.hWnd.
- For user-defined interfaces, the wizard creates both class and interface definitions—To define a new interface in VB 6.0, you had to create a new class. Behind the scenes, the default interface of this class was used by the compiler when you implemented your "interface class" in another class. However, VB.NET provides a specific keyword allowing you to define an interface.
For example, in the custom VertexLineSymbol developer sample, there is a class called IVertexLineSymbol that defines a custom interface. During the upgrade process, the wizard created both the class and the hidden default interface for the class, resulting in a class called IVertexLineSymbol and an interface called _IVertexLineSymbol. The _IVertexLineSymbol interface will be implemented by both the IVertexLineSymbol interface class and the actual custom symbol class VertexLineSymbol (try the conversion to understand more about this issue).
As VB.NET provides the interface keyword, you can remove the class interface, leaving just the interface definition. You may want to rename the interface by removing the underscore prefix (do not forget to update any other uses of the interface throughout your code if you do rename the interface). In the example of the VertexLineSymbol developer sample, remove the IVertexLineSymbol class and leave the _IVertexLineSymbol declaration. Rename the interface to IVertexLineSymbol and change any other references in the code—including the Implements statement in the VertexLineSymbol class.
The following is not an essential step, but it will help reduce complexity in your project and cut a few unnecessary calls at runtime.
- Couldn't resolve default property of object <variable name>—This warning is commonly found in upgraded projects and can often be ignored. This warning is due to a combination of the following two factors:
- During the upgrade process, default properties for early-bound objects are resolved to the fully qualified property name. However, default properties for late-bound objects cannot be resolved as the default property cannot be known in advance.
- It is common in VB 6.0 code to perform an implicit cast, where a property requiring a certain interface is set to a variable that is a different interface, but that underlying object does support the required interface. Implicit casting is allowed in Visual Basic when Option Strict is turned off, but not when Option Strict is turned on. Iis also not allowed in Visual C#.
The upgrade wizard highlights lines of code where types are late bound when an implicit cast is made, as it assumes a default property is being used to access the correct type—for example, creating a new AlgorithmicColorRamp and setting its FromColor property from a red, green, and blue (RGB) color as shown in the following code example:
Dim pAlgoColorRamp As IAlgorithmicColorRamp Set pAlgoColorRamp = New AlgorithmicColorRamp Dim pRGBColor As IRgbColor Set pRGBColor = New RgbColor pAlgoColorRamp.FromColor = pRGBColor ' FromColor property requires an IColor reference.
These lines of code caused an upgrade warning indicating the default property of the object pRGBColor cannot be resolved. However, the code is correct and there is no default property being used as an implicit cast is made to the IColor interface of the IRGBColor reference pRGBColor. However, as the FromColor property requires an IColor reference and pRGBColor is an IRGBColor reference, the wizard assumes a default member is being used to return the correct type—it does not know that an implicit cast is made between these interfaces in VB 6.0. You can ignore these cases or just add explicit casting if required, for example, if Option Strict is turned on. See the following code example:
Dim pAlgoColorRamp As ESRI.ArcGIS.Display.IAlgorithmicColorRamp = New ESRI.ArcGIS.Display.AlgorithmicColorRamp Dim pRGBColor As ESRI.ArcGIS.Display.IRgbColor = New ESRI.ArcGIS.Display.RgbColor pAlgoColorRamp.FromColor = DirectCast(pRGBColor, ESRI.ArcGIS.Display.IColor)
The following information shows how to deal with issues—for ArcObjects code in .NET—that may not be highlighted by the upgrade wizard related specifically to ArcObjects API or Component Object Model (COM) interop:
Use OLE- automation-compliant interfaces—When programming with ArcObjects in .NET, use any Object Linking and Embedding (OLE) automation-compliant interfaces that are available. These interfaces avoid the use of, for example, C-style arrays that are not part of the OLE standard and are not supported by .NET. For more information on this issue, see Migrating from 8.x to 9.x.
OLE-compliant interfaces are named with the suffix GEN. For example, you may have used the IEnvelope.DefineFromPoints method in VB 6.0, which uses a C-style array and does not operate correctly if used from .NET. Therefore, you should instead use the OLE-compliant IEnvelopeGEN.DefineFromPoints method. In some cases, OLE-compliant alternatives for members on a number of interfaces are grouped together on bridge interfaces; for example, IGeometryBridge or IGeoDatabaseBridge. The use of GEN and bridge interfaces is not accounted for by the code converter and will need to be handled manually.
- COM registration and attributes—If you have a VB 6.0 ActiveX dynamic-link library (DLL) project that you want to upgrade to a .NET class library registered for COM interop (for example, a library providing custom objects to ArcGIS), set the project-level Register for COM Interop option. Also, add any appropriate attributes as the upgrade wizard will not carry out either of these steps. For more information on registering for COM interop and using attributes, see the MSDN Web site, Interoperating with COM, and How to register .NET components with COM.
- Component category registration—In VB 6.0, the compile and register add-in can be used to create .reg files that can be used to register custom classes to ESRI component categories at compile time and also during deployment. In .NET, this approach is replaced by the .NET integrated development environment's (IDE) ArcGIS Component Category Registrar dialog box to achieve similar end results by utilizing built-in functionality available in .NET.
Use base classes for commands and tools—Conversion results in a project that does not use the ESRI base classes for commands and tools. These base classes can help you create code that is easy to maintain. Therefore, you may want to refactor any command or tool custom classes in your project to inherit from the base classes after the conversion is complete. For more information about the base classes, see Working with the ArcGIS base classes.
The following information discusses issues you may encounter when migrating code from VB 6.0 to .NET that are not highlighted by the upgrade wizard and are not specifically related to ArcObjects:
- OLE_HANDLE values (for example, ICommand.Bitmap or ITool.Cursor properties)—The following two separate but related issues are involved in upgrading some members returning an OLE_HANDLE type:
- You may find an upgrade issue listed indicating "cannot implement <member> because there is no matching property on the interface <interface>". Refer to the previous discussion for more information.
- Once the return type of the member declaration is corrected, you will be left in many cases with a remaining issue of how to return the correct OLE_HANDLE. In the case of returning the window handle (hWnd) of a form or other control as a hWnd, you may find that the Handle property of a control will provide a suitable equivalent. However, taking the example of ICommand.Bitmap, ArcGIS expects the returned integer to be a pointer to a Windows Graphical Device Interface (GDI) bitmap; in VB 6.0, it was common to achieve this by retrieving the handle device context (HDC) property of an OLE picture object, using the Stdole library.
However, .NET uses GDI+ objects for drawing. Therefore, a .NET bitmap object is not equivalent to an OLE picture, and a .NET image object has no HDC property. The simplest way to solve this issue for a command or tool (including returning ITool.Cursor) is to refactor your code to make use of the base classes. You can also use code similar to the following to return a handle to a GDI bitmap from a GDI+ bitmap object; if you do use the GetHBitmap method as shown in the following code example, verify that you use the corresponding handle cleanup code—for more information about this method, see MSDN. You should only need to create the handle once and store this to return from the property as required.
' Declaration for the handle clean-up function. Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As IntPtr) As Boolean ... Dim bm As New System.Drawing.Bitmap(frmResources.DefInstance.Picture3.Image) Dim hBitmap As IntPtr = bm.GetHbitmap() Return hBitmap.ToInt32() DeleteObject(hBitmap
Upgraded events code—If you use the upgrade wizard on projects that include event handling, you could find problems if attempting to use the nondefault events interface. VB 6.0 is unable to sink the events of a nondefault event interface, and ESRI instead provides the helper classes to allow VB 6.0 programmers access to nondefault event interfaces. For example, the Map class has IActiveViewEvents as its default event interface, but VB 6.0 programmers can use the helper classes MapEvents, MapEvents2, and MapEvents3 to access the nondefault IMapEvents, IMapEvents2, and IMapEvents3 event interfaces. Once upgraded to VB.NET, the code is the same as that originally in VB 6.0. See the following code example:
' Declare the helper class for IMapEvents as WithEvents. Private WithEvents m_pMapEvents As ESRI.ArcGIS.Carto.MapEvents ... Public Sub SomeSetupFunction() ' Initialize the MapEvent variable. m_MapEvents = doc.FocusMap End Sub Private Sub m_MapEvents_FeatureClassChanged(ByVal oldClass As ESRI.ArcGIS.Geodatabase.IFeatureClass, _ ByVal newClass As ESRI.ArcGIS.Geodatabase.IFeatureClass) Handles m_MapEvents.FeatureClassChanged ' Listen to the FeatureClassChanged event of IMapEvents. End Sub
However, when you set the m_pMapEvents2 variable in .NET, an exception is raised, indicating that the specified cast is invalid.
If you do not have any exception handling, you may not be aware that this situation is occurring.
To solve this issue, you can use the AddHandler method of events sinking rather than using the WithEvents keyword—this means that instead of declaring module-level variables WithEvents, you will instead declare delegates and wire these to the appropriate events. In the previous example of the IMapEvents2 event interface, this can be changed to use code similar to the following:
' Declare a delegate for the FeatureClassChanged event. Private dFeatClsChangedE As ESRI.ArcGIS.Carto.IMapEvents_FeatureClassChangedEventHandler ... Public Sub SomeSetupFunction() ' Initialize the MapEvent variable. Dim mapEvents As ESRI.ArcGIS.Carto.IMapEvents_Event = CType(doc.FocusMap, ESRI.ArcGIS.Carto.IMapEvents_Event) ' Initialize the delegate to point to a function where you respond to the event being raised. dFeatClsChangedE = New ESRI.ArcGIS.Carto.IMapEvents_FeatureClassChangedEventHandler(AddressOf OnFeatureClassChangedFunction) ' Wire the delegate to the FeatureClassChanged event of the mapEvents variable. AddHandler mapEvents.FeatureClassChanged, dFeatClsChangedE End Sub Private Sub OnFeatureClassChangedFunction(ByVal oldClass As ESRI.ArcGIS.Geodatabase.IFeatureClass, _ ByVal newClass As ESRI.ArcGIS.Geodatabase.IFeatureClass) ' Listen to the FeatureClassChanged event of IMapEvents. End Sub
For more information on using AddHandler, see the following topics in the Programming with .NET section in this help system:
- How to wire ArcObjects .NET events
- How to listen to document events
- Wiring custom events using IActiveViewEvents
- How to listen to versioned events
- Wiring events in ArcGIS Desktop using IActiveViewEvents
Using AddHandler requires more coding, as this is less automated in the Visual Studio .NET IDE. However, it has the advantages of being more flexible and more directly translatable to equivalent C# code.
Security exceptions on remote projects—If you are accustomed to saving your VB 6.0 projects in a location other than your local machine, you can run into unexpected security errors when you migrate to .NET and save your project in a similar location. You could find a SecurityException is raised at runtime or you could receive an error message when you open the project, such as: The project location is not fully trusted by the .NET runtime.
This is usually because it is a network share or mapped to a network share not on the local machine. If the output path is under the project location, your code will not execute as fully trusted and you could receive unexpected security exceptions. To avoid this, change the trust of Local Intranet zone in the .NET Framework Configuration to allow you to run applications that are on a network drive apart from your machine. This is because the default security model of the .NET framework is more restrictive than that of ActiveX or Win32 code. The following are a few alternatives to resolve this issue:
- You can copy your project to a local drive.
- It may also be possible to set the output folder of your project to a local folder. This means that the executable code is stored locally; therefore, it does not cause a security exception but the source code remains at its network location.
- You can alter the security settings in the .NET framework to allow execution of code from a network location—change these settings by using the .NET Framework Configuration wizard found in the administrative tools.
This requires changing the default security of the .NET framework. Always check with your system administrator to ensure this does not violate any local or domain security policies.
The following are the basic permissions that you will need to run interop code from a network path:
- FileIO permission.
- Enable execution.
- Allow calls to unrestricted code security permissions and—depending on your code—user interface permission; however, usually you will need to add other permissions depending on what actions your code performs.
See Also:Interoperating with COM
How to register .NET components with COM
Working with the ArcGIS base classes