Chapter 14: Interop Between Visual Basic 6.0 and Visual Basic .NET

How to achieve interoperability between Visual Basic 6 and .NET? Because the .NET Framework was designed from the ground up to communicate with COM components, the process should not be difficult; as a matter of fact, you will be able to access .NET components and assemblies from VB6 or viceversa by using the approaches and techniques described in this chapter.

Why is it so important to perform a functional analysis of the application prior to an upgrade?

Because this will enable you to identify the functional components of the application, and to build a more effective plan for the overall upgrade process. It also helps you to improve your application by identifying redundant or unused code modules that should be eliminated to reduce the amount of work that will be required for the upgrade. After you identify the components that must be upgraded to Visual Basic .NET and those that can remain in Visual Basic 6.0 (either temporarily or permanently), you can begin to create an effective interoperability between components.

Can Visual Basic .NET applications access VB 6.0 components and vice versa?

The .NET Framework was designed from the ground up to interoperate with COM. COM components can call .NET assemblies, and vice versa. Furthermore, .NET assemblies can be built to be referenced just like COM components are referenced. To do this, you build your assembly so that it is COM-callable, and your code will be able to reference the assembly’s functionality and interfaces.

COM-callable assemblies can be referenced from Visual Basic 6.0 applications as if they were ordinary COM components. In this case, interoperability may be as simple as referencing the correct assembly’s type library (.tlb file) and accessing the desired functionality.

On the other hand, to access Visual Basic 6.0 code from Visual Basic .NET clients, you must expose the Visual Basic 6.0 code as a COM component, and then reference it as such from the Visual Basic .NET client.

How can interoperability between Visual Basic 6.0 and VB .NET be achieved?

There are two approaches: to use direct access through COM, requiring that the .NET assembly to be referenced is created as a COM-callable assembly, or to create a COM-callable wrapper using a .NET language for the functionality you want to access.

What are the requirements for accessing .NET components from a Visual Basic 6.0 application?

Every .NET component that is going to be accessed from Visual Basic 6.0 must be registered for interoperability in the system. Registration takes place at a global level and will make the component available to all Visual Basic 6.0 applications. An assembly is the primary building block of a .NET application and it can contain different classes that are available to COM clients. Registering an assembly will make the classes in a registered assembly available to all Visual Basic 6.0 applications on the system.

The process to register a .NET assembly and make it COM-callable involves creating a type library (.tlb) and including the corresponding entries in the system registry. This is easily accomplished from within the Visual Studio .NET IDE by setting the appropriate build configuration option.

What requirements should be met for a .NET managed type to be exposed to COM clients?

  • Managed types must be public. Only public types in an assembly are registered and exported to the type library. As a result, only public types are visible to COM.
  • Methods, properties, fields, and events must be public. Members of public types must also be public if they are to be visible to COM. You can restrict the visibility of an assembly, a public type, or public members of a public type by applying the ComVisibleAttribute. By default, all public types and members are visible.
  • Types must have a public default constructor to be activated from COM. Managed public types are visible to COM. However, without a public default constructor (a constructor with no arguments), COM clients cannot create the type.
  • Types cannot be abstract. Neither COM clients nor .NET clients can create abstract types.
  • Certain Visual Basic .NET features will prevent a method from being COM callable. Shared (static) Visual Basic .NET methods cannot be called from COM objects. Also, methods should take and return simple data types such as Integer or String. If a method takes or returns a type that was not designed for COM interop, the method will not be callable from Visual Basic 6.0.

What is the general procedure to access .NET assemblies directly from Visual Basic 6.0?

  1. Determine the assembly you want to access.
  2. Locate the assembly’s type library.
  3. In your Visual Basic 6.0 application, add the reference to the assembly’s desired type library.
  4. Invoke the required functionality from the assembly.

So what are the exact steps to access a .NET assembly from a Visual Basic 6.0 application?

You can follow these steps:

  1. Register the assembly to be accessed. This allows Visual Basic 6.0 to instantiate and access the .NET assembly.
  2. Start Visual Basic 6.0.
  3. In the New Project dialog box, click Standard.exe to create the new project.
  4. On the Project menu, click References. This displays the References dialog box where you can select the COM components and the registered COM-callable .NET assemblies that your application will reference.
  5. In the References dialog box, click Browse.
  6. In the Add Reference dialog box, navigate to the directory where the System.tlb file is located.
  7. Click the .tlb file for the assembly you want to reference, and then click Open. In this example, you would click System.tlb.
  8. In the Available References list, select the check box for the Visual Basic .NET library you want to reference, and then click OK.

After completing these steps, you can reference any interface and public class contained within the assembly from your Visual Basic 6.0 project.

How can I mitigate the limitations that come from directly accessing the .NET Framework Class Library (FCL)?

In such cases, you can create a COM-callable wrapper object in Visual Basic .NET, and reference the wrapper object from Visual Basic 6.0. Creating a wrapper involves several steps, including creating a type library (.tlb) file for the wrapper class and registering the class for COM interoperability.

Using wrappers gives you access to the full range of available .NET assemblies through Visual Basic .NET. It also allows you to better modularize your code by avoiding granular invocations of the .NET assemblies where they’re not necessary.

How do I register a Visual Basic .NET component for COM interop?

  1. Open the project for your Visual Basic .NET wrapper class.
  2. On the Project menu, click Properties.
  3. In the Configuration Properties folder, click Build.
  4. Select the Register for COM Interop check box, and then click OK.
  5. On the File menu, click Save to save your project with the configuration changes.
  6. On the Build menu, choose Build Solution.

How do I register a .NET assembly using command-lines tools?

  • 1. Compile the wrapper class using the Visual Basic .NET compile command vbc.exe.
  • 2. Register the assembly and generate a type library so that it appears as a regular COM object.

What is data type marshaling?

Marshaling is the process of packing and unpacking parameters and return values in a way that enables the execution of a cross platform invocation. As mentioned earlier, COM is the key to achieving interoperability between Visual Basic 6.0 and Visual Basic .NET. It is because of the presence of COM that data type marshaling becomes a non-issue in cases where components in different thread apartments interact. The .NET interoperability marshaling enables the interaction between different data types in managed and unmanaged memory. Interop marshaling is performed at run time by the CLR’s marshaling service when functions are invoked within the same COM apartment. When the interaction takes place between managed code and unmanaged code in a different COM apartment or a different process,both the interop marshaler and the COM marshaler are executed.

What is HRESULT and what is its role in error management?

As mentioned previously, .NET uses a structured exception handling approach for indicating, and reacting to, both anticipated and unanticipated error conditions. This is not the case in Visual Basic 6.0. (Although the OnError handler provides a process that can be considered similar to exception handling, it does not behave the same way.)

Because interoperability between Visual Basic .NET and Visual Basic 6.0 is achieved using COM-based mechanisms, there is an inherent value, named HRESULT, which is passed back and forth between the Visual Basic 6.0 code and the .NET assembly. Even though this happens behind the scenes, it is still there. In Visual Basic 6.0, this value can be accessed through the Err.Number property. In Visual Basic .NET, this value is treated differently depending on whether or not the original exception is a standard exception.

How do I handle application errors that are raised in the form of .NET exceptions?

You must inspect the Number property of the Visual Basic 6.0 Err object, and to select an execution path based on its value. This technique can also be applied to standard exceptions like overflow or divide-by-zero exceptions.

What is the procedure for sinking events for COM client consumption from Visual Basic 6.0?

This is done through the RaiseEvent statement. These events can also be caught and handled by .NET code as if they were originating from a COM component. The Visual Basic 6.0 event producer code raises a Divide event whenever the DoDivide function is invoked and raises a Multiply event when the DoMultiply function is invoked. The consumer code, written in Visual Basic .NET, provides the event handlers OnDivide and OnMultiply to catch and handle each event whenever they occur.

What kind of properties does the Visual Basic 6.0 App object provide?

The Visual Basic 6.0 App object provides a group of properties that can be used to specify parameters for the interaction and synchronization with an OLE Automation server during the invocation of one of its methods.

The first set of properties is related to the time that the application will retry a failed automation call request. After the specified time elapses, a customizable dialog box automatically displays in the application. This dialog box informs the user about the busy state of the OLE server. This behavior is controlled with the properties: OleServerBusyMsgText, OleServerBusyMsgTitle, OleServerBusyRaiseError, and OleServerBusyTimeout.

The second set of properties is related to the time an application will wait for an OLE Automation request to be completed. This group of properties works in a similar way to the previous group and includes: OleRequestPendingMsgText, OleRequestPendingMsgTitle, and OleRequestPendingTimeout.

In .NET, what is the garbage collection mechanism responsible for?

The garbage collection mechanism is responsible for the invocation of component’s destructors when the component cannot be accessed by any executing code. This condition is reached when all references to the component have been released or belong to objects that are isolated from all running code.

What are the main differences between VB .NET and VB 6.0 in terms of releasing resources that will no longer be used?

The .NET Framework uses a technique called reference-tracing garbage collection, while Visual Basic 6.0 used a different system called reference counting with the same purpose. These systems have the following main differences that must be considered in order to achieve successful interoperation:

  • Non-deterministic object lifetime. The CLR destroys objects more quickly when system resources decrease to a certain level; on the other hand, objects are destroyed slower when system resources abound. The result of this scheme is that it is impossible to determine in advance when an object will actually be destroyed and its resources freed under Visual Basic .NET. In this case, .NET objects are said to have a non-deterministic lifetime. This behavior does not affect the development process, as long as it is understood that the Finalize destructor may not execute immediately when an object goes out of scope under Visual Basic .NET.
  • Assignment of the Nothing value. In Visual Basic 6.0, programmers can affect the reference count for an object by assigning Nothing to one of the corresponding object variables. When the reference count reaches zero, the object resources are immediately released. In Visual Basic .NET, an assignment with a Nothing value will never produce an immediate release; if this is necessary, the Dispose method must be implemented and explicitly invoked at the desired time.