Replacing COM with .NET: Binary Compatibility

Replacing COM with .NET: Binary Compatibility

In creating Visual Basic versions 4, 5, and 6, the Microsoft Visual Basic development team worked hard to allow you to create Visual Basic COM components that are backward compatible. This feature was enabled by an innocent-looking check box on the Component tab of the Project Properties dialog box, shown earlier in Figure 9-6. Binary compatibility in Visual Basic 6 enabled you to create version 2 of a COM component that is a compatible replacement for version 1 of that component. What this means is that the version 2 component contains exactly the same public objects, properties, methods, and events as the version 1 component. In addition, it means that the properties, methods, and events appear in exactly the same order as in the version 1 component. The version 2 component also understands how to initialize itself using property settings saved by the version 1 component.

Although the version 2 component needs to look, act, and smell like a version 1 component, the version 2 component can include additional objects, properties, and methods that improve upon the version 1 component. No matter the improvements, however, in order to keep clients of the version 1 server component working with the version 2 component, the version 2 component must expose some subset of itself as a version 1 component. If the version 2 component doesn t expose itself as a version 1 component, you need to do one of the following:

  1. Invest in fixing the version 2 component to behave identically to the version 1 component and then invest further in testing the component to ensure that no existing version 1 clients are broken by the changes.

  2. Rename the version 2 component and change its attributes in such a way that it exposes itself as a completely new component. Clients that are using the version 1 component continue to use that component and are not disturbed by the distribution of the version 2 component.

  3. Recompile all clients that use the version 1 component to use the version 2 component and then distribute the client and a version 2 server component as a matched pair.

Which option makes more sense? Option B is generally the recommended approach if you have widely distributed clients that rely on version 1 of the server component. If there is any doubt in your mind about whether you can update an existing component or create a new component as a direct replacement of a version 1 component, don t do it. Instead, go with option B. It s the safe bet.

When it comes to creating Visual Basic .NET components that are direct replacements of your Visual Basic 6 components, Visual Basic .NET adopts the option B approach. Simply put, you can t do it, although if the truth be told, it s possible but not easy. You ll sleep much better if you simply assume that you can t directly replace a Visual Basic 6 component with a Visual Basic .NET one.

The Visual Basic team deliberately chose not to include features that would make it easy for you to mark a Visual Basic .NET component as being a compatible replacement for a Visual Basic 6 component. We ll let the following Visual Basic code speak for itself:

Const Old_compiler = "VB6.EXE" Const New_compiler = "VBC.EXE" Const Old_runtime = "MSVBVM60.DLL" Const New_runtime = ".NET Framework and Microsoft.VisualBasic.Dll" If New_compiler <> Old_compiler And New_runtime <> Old_runtime Then    MsgBox "Minor behavioral differences that are expensive to " & _           "find and fix" End If

Indirect Replacement Model

Visual Basic .NET takes an indirect approach in creating Visual Basic .NET components that are replacements of your Visual Basic 6 COM components. This approach means that you can create a component that looks and smells like a Visual Basic .NET component but doesn t necessarily act 100 percent like the Visual Basic 6 component it s replacing. Since to take advantage of new version 2 component features you need to update your existing clients, why not live a little and roll those features into a Visual Basic .NET component? Putting the new features in a separate component has the advantage of not disturbing the version 1 component. Clients that are running against the version 1 component continue to run against it, unaffected by the changes in the version 2 component. When you are ready to move your clients to the version 2 component, you can update and redistribute them as needed.

By using the Visual Basic Upgrade Wizard, you can quickly upgrade your Visual Basic 6 components to Visual Basic .NET components. Although the wizard doesn t give you a full, 100 percent binary-compatible replacement for your Visual Basic 6 component, what you end up with is pretty close. All properties, methods, and events are brought forward, preserving the public interface of your component. Once you have worked out all of the upgrade-related comments and issues in the upgrade report, you can effectively replace your Visual Basic 6 component with the .NET version by making a quick change to the Visual Basic 6 client application so that it uses your .NET component instead of the Visual Basic 6 component. You then need to rebuild and redeploy your Visual Basic 6 application to take advantage of the new Visual Basic .NET server component.

Enabling Binary Compatibility in Visual Basic .NET Classes

If you want to expose your upgraded Visual Basic .NET server component to a COM client and you plan on making changes to the Visual Basic .NET server component over time, we strongly suggest that you do the following to ensure compatibility:

  • Declare all the public class properties and methods in an interface.

  • Declare all the public events in a separate event interface.

  • Add attributes to the class to declare ID attributes for the class, interface, and event interface.

  • Change the class declaration so that it implements both the programmable and event interfaces.

Let s step through an example that demonstrates how to enable binary compatibility in a Visual Basic .NET class. Doing so will ensure that a COM client that uses the class will continue to work with it even after you have added new functionality to the class.

We ll start with a Visual Basic .NET class that was upgraded from Visual Basic 6. Assume that the filename for the class is Class1.vb.

Option Strict Off Option Explicit On  Public Class Translator    Public Event TranslationError(ByVal ErrorMessage As String)    Public Function Translate(ByVal SentenceFrom As String, _                              ByVal LanguageFrom As String, _                              ByVal LanguageTo As String) As String       Dim fSuccess As Boolean       ' Note to self: Find someone who speaks Spanish and VB who       ' is willing to expand this component to translate any common        ' English phrase       If LCase(LanguageFrom) = "english" And _          LCase(LanguageTo) = "spanish" Then          Select Case LCase(SentenceFrom)             Case "hello world"                Translate = "hola mundo"                fSuccess = True          End Select       End If       If Not fSuccess Then          RaiseEvent TranslationError( _             "Translation not implemented for " & SentenceFrom)       End If    End Function End Class

  1. Choose Add New Item from the Project menu and select COM Class. This gives you a template class for creating binary compatible objects.

  2. Copy and paste the public event TranslationError and the public method Translate to the new COM class. Paste the code after Sub New.

  3. Right-click Class1.vb in the Solution Explorer and delete it. We no longer need it.

  4. View the code for ComClass1 and expand the #Region COM GUIDs, since you will need to use these values later.

  5. Change the Public Class declaration for ComClass1 to Translator as follows:

    Public Class Translator

  6. Add the following Imports clause to the top of the file as follows. COM attributes such as Guid and ComVisible will come from this namespace.

    Imports System.Runtime.InteropServices

  7. Replace the ComClass attribute in the Translator class with the following attributes:

    <Guid(ClassId), ComVisible(True)> _ Public Class Translator

  8. Define the programmable interface containing the Translate method. Define the interface after the #End Region for COM GUIDs as follows:

    <Guid(InterfaceId)> _ Interface ITranslate    <DispId(1)> _    Function Translate(ByVal SentenceFrom As String, _                       ByVal LanguageFrom As String, _                       ByVal LanguageTo As String) As String End Interface

  9. Immediately following the programmable interface, insert the declaration for the event interface as follows:

    <Guid(EventsId)> _ Interface ITranslateEvents    Event TranslationError(ByVal ErrorMessage As String) End Interface

  10. Add an Implements clause after the Public Class declaration to implement the programmable and event interfaces you just declared as follows:

    Public Class Translator    Implements ITranslate, ITranslateEvents

  11. Modify the Public Event declaration to implement the interface event as follows:

    Public Event TranslationError(ByVal ErrorMessage As String) _    Implements ITranslateEvents.TranslationError

  12. Modify the public Translate method to implement the ITranslate.Translate interface method as follows:

    Public Function Translate(ByVal SentenceFrom As String, _ ByVal LanguageFrom As String, _ ByVal LanguageTo As String) _                              As String _ Implements ITranslate.Translate

When completed, you should have the following class with all the necessary COM attributes defined. You can rebuild the class without breaking compatibility with existing COM clients. The only way you will break compatibility is if you consciously change GUIDs, change a method or event signature, or change the order of events or methods defined in an interface. To maintain compatibility from this point on, you must restrict yourself to adding new methods to the end of an interface. You can never remove or change an existing method, nor can you can change the order of the methods.

Imports System.Runtime.InteropServices <Guid(ClassId), ComVisible(True)> _ Public Class Translator    Implements ITranslate, ITranslateEvents #Region "COM GUIDs"    ' These  GUIDs provide the COM identity for this class     ' and its COM interfaces. If you change them, existing     ' clients will no longer be able to access the class.    Const ClassId As String = "4B33F612-69C0-4270-A7F3-1B460EBDE978"    Const InterfaceId As String = _       "D1C5A219-A6C9-46CA-939F-8CF2D22FE441"    Const EventsId As String = "86215D08-D4AD-4CA8-9BAC-01E8A592812D" #End Region    <Guid(InterfaceId)> _    Interface ITranslate       <DispId(1)> _       Function Translate(ByVal SentenceFrom As String, _                          ByVal LanguageFrom As String, _                          ByVal LanguageTo As String) As String    End Interface    <Guid(EventsId)> _    Interface ITranslateEvents       Event TranslationError(ByVal ErrorMessage As String)    End Interface    ' 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()    End Sub    Public Event TranslationError(ByVal ErrorMessage As String) _       Implements ITranslateEvents.TranslationError    Public Function Translate(ByVal SentenceFrom As String, _                              ByVal LanguageFrom As String, _                              ByVal LanguageTo As String) As String _                              Implements ITranslate.Translate       Dim fSuccess As Boolean       ' Note to self: Find someone who speaks Spanish and VB who       ' is willing to expand this component to translate any common        ' English phrase       If LCase(LanguageFrom) = "english" And _          LCase(LanguageTo) = "spanish" Then          Select Case LCase(SentenceFrom)             Case "hello world"                Translate = "hola mundo"                fSuccess = True          End Select       End If       If Not fSuccess Then          RaiseEvent TranslationError( _             "Translation not implemented for " & SentenceFrom)       End If    End Function End Class

note

In order to control the binary compatibility of components, many of you asked for a Visual Basic feature to expose COM attributes such as Guid and method IDs in a Visual Basic class. Visual Basic 6 offers a simple way to enable binary compatibility the Binary Compatibility option but does not allow you to define or edit the COM attributes that it automatically generates for you. Visual Basic .NET does not offer any simple solution to binary compatibility; there is no binary compatibility option that you can turn on. Instead, you must write code manually defining the interfaces and COM attributes to enforce binary compatibility. The ability to specify COM attributes comes at a cost: more code. After you have beautified your code by manually adding these attributes, you may ask what you have gotten yourself into. Be careful what you ask for particularly if you ve requested more control in specifying COM attributes; you just might get it.



Upgrading Microsoft Visual Basic 6.0to Microsoft Visual Basic  .NET
Upgrading Microsoft Visual Basic 6.0 to Microsoft Visual Basic .NET w/accompanying CD-ROM
ISBN: 073561587X
EAN: 2147483647
Year: 2001
Pages: 179

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net