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?
- Determine the assembly you want to access.
- Locate the assembly’s type library.
- In your Visual Basic 6.0 application, add the reference to the assembly’s desired
type library.
- 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:
- Register the assembly to be accessed. This allows Visual Basic 6.0 to instantiate
and access the .NET assembly.
- Start Visual Basic 6.0.
- In the New Project dialog box, click Standard.exe to create the new project.
- 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.
- In the References dialog box, click Browse.
- In the Add Reference dialog box, navigate to the directory where the System.tlb
file is located.
- Click the .tlb file for the assembly you want to reference, and then click Open.
In this example, you would click System.tlb.
- 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?
- Open the project for your Visual Basic .NET wrapper class.
- On the Project menu, click Properties.
- In the Configuration Properties folder, click Build.
- Select the Register for COM Interop check box, and then click OK.
- On the File menu, click Save to save your project with the configuration changes.
- 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.