Extending Visual Basic 6 ActiveX EXEs With Visual Basic 2005 and the Interop Forms Toolkit
Updated: March 2007
Visual Basic 6
Visual Basic 2005
Summary: This article discusses techniques for modernizing and upgrading Visual Basic 6 ActiveX EXEs with Visual Basic 2005. In addition to examining strategies to move ActiveX functionality onto the .NET Framework, this article also demonstrates: How to modernize an existing ActiveX EXE by including Visual Basic 2005 Windows Forms using the Interop Forms Toolkit, and how to access business logic in a Visual Basic 6 ActiveX EXE from within a Visual Basic 2005 application. (12 printed pages)
Download the associated sample code.
About ActiveX EXEs
ActiveX EXEs and Visual Basic 2005
Moving ActiveX EXEs Forward to Visual Basic 2005
Modernizing ActiveX EXEs Using Visual Basic 2005
Calling ActiveX EXEs from Visual Basic 2005
ActiveX EXEs are a versatile yet relatively uncommon application type unique to Visual Basic 6 development. These are applications that exhibit dual behavior: they can operate either as a standalone executable or as a DLL code library. ActiveX EXEs create an issue for developers moving their codebase forward to Visual Basic 2005 since ActiveX EXEs can neither be migrated to Visual Basic 2005, nor can they be created by or consumed from a .NET application.
The release of the Visual Basic 2005 Interop Forms Toolkit makes working with ActiveX EXEs easier: the Interop Forms Toolkit provides new capability that allows ActiveX EXEs to be extended with new .NET objects. In addition, Visual Basic 2005 makes the process of working with COM objects easier and more seamless than previous versions of Visual Basic.
This article shows how to add a Visual Basic 2005 form to a Visual Basic 6 ActiveX EXE and interact with the form. It also demonstrates how to invoke classes in a Visual Basic 6 ActiveX EXE from a Visual Basic 2005 application, and discusses options for upgrading code within an ActiveX EXE.
The Visual Basic Interop Forms Toolkit forms the basis of this solution. This toolkit is a free download that enables a Visual Basic 6 form to open a Visual Basic 2005 form, invoke methods, and use a shared property bag to pass state between the forms.
ActiveX EXEs are a feature of Visual Basic 5 and Visual Basic 6 development. They are code library DLLs that can also be run as an executable. ActiveX EXEs differ from traditional DLLs in several ways:
- Run in their own process. Whereas normal DLLs run in the memory process of their parent application, ActiveX EXEs run in their own process. This means they show up as separate applications in Task Manager. It also means ActiveX EXEs are slower than DLLs since Windows has to do extra work to marshal variables when they are passed to and from an ActiveX EXE.
- Class instancing. ActiveX EXEs have two class instancing modes not available to normal DLLs and executables: SingleUse and GlobalSingleUse, both of which ensure that a separate copy of the class is loaded into memory whenever an instance is created.
- Remote execution. It is possible to invoke classes in an ActiveX EXE on a remote computer. In Visual Basic 5 and Visual Basic 6, the only other way to execute code on a remote computer was by creating DLLs hosted in Microsoft Transaction Server.
- Multi-threading. Because ActiveX EXEs run in their own process, they are allocated their own thread. In theory, this enables multi-threading in a Visual Basic 5 or Visual Basic 6 application. In practice, this is problematic since the calling application must wait for the called method in the ActiveX EXE to finish execution before continuing, giving a user-experience that is the same as a single-threaded application.
The two most common uses for ActiveX EXEs are for running code on remote computers and for creating executables that also act as a code library.
Neither creating nor consuming ActiveX EXEs is explicitly supported in Visual Basic 2005. The .NET platform underlying Visual Basic 2005 provides better mechanisms for achieving the same result:
- Remote execution. WebServices and .NET remoting provide a more robust, secure and thorough mechanism for executing code on remote computers.
- Multi-threading. Visual Basic 2005 has first-class support for creating multithreaded applications with fine-grained control over thread creation, destruction and prioritization, as well as mutexes and semaphores.
- DLLs and executables. Although Visual Basic 2005 does not support executables that double as class libraries, the product has much better support for different types of executables such as console applications, Windows applications, Windows services, web applications and easily versioned DLLs that are not vulnerable to the "DLL hell" versioning problems common to COM applications.
The Visual Basic 2005 upgrade wizard cannot upgrade a Visual Basic 6 ActiveX EXE. If you try to upgrade an Active EXE project, the upgrade wizard warns that upgrading ActiveX EXEs is not supported, and then exits.
For developers who have a compelling business need to overhaul an ActiveX EXE, standardizing on Visual Basic 2005 is an appropriate strategy which means finding a way to upgrade or rewrite the entire ActiveX EXE to Visual Basic 2005.
Upgrading the ActiveX EXE code
Some or most of the business logic in a Visual Basic 6 ActiveX EXE can usually be automatically upgraded to Visual Basic 2005, with some rework required after the upgrade wizard is finished.
Although the Visual Basic 2005 upgrade wizard does not support upgrading Visual Basic 6 ActiveX EXEs, with a little trickery, the Visual Basic 2005 upgrade wizard can be fooled into performing the upgrade.
To upgrade an ActiveX EXE project, change the project type from "ActiveX EXE" to "ActiveX DLL" in the Visual Basic 6 project properties. After doing this, the upgrade wizard recognizes the project as a code library rather than an ActiveX EXE. The resulting Visual Basic 2005 project will be a DLL rather than an executable.
Figure 1. Changing the project type to ActiveX DLL
This is a useful technique for upgrading business objects and logic, although the specific ActiveX EXE functionality will not be moved forward.
If upgrading the ActiveX EXE creates a huge number of upgrade issues, you may choose to use the snippet upgrade utility which helps with upgrading fragments of Visual Basic 6 code to Visual Basic 2005. To find the snippet upgrade utility, first open the Visual Basic 2005 code editor, then choose the Tools > Upgrade Visual Basic 6 Code... menu item.
Whether you choose to rewrite the ActiveX EXE or use the Visual Basic 2005 upgrade technologies, you will need to re-create the ActiveX EXE capabilities using Visual Basic 2005 capabilities. The following section gives an overview for how to do this.
Recreating ActiveX EXE Capabilities in Visual Basic 2005
As mentioned earlier in this article, there are two main uses for Visual Basic 6 ActiveX EXEs—running code on another machine and creating an executable that also acts as a class library. This section gives an overview and provides resources for achieving the same result in a Visual Basic 2005 application. It also discusses multi-threading, another common feature of ActiveX EXEs.
Running code on another machine
In Visual Basic 2005 there are two common methods for running code on another machine: .NET Remoting and XML WebServices. Both methods enable an application to invoke a method on a remote machine and return a result to the calling application. The main difference between the two techniques is that .NET Remoting requires you to write a bit more plumbing code, and has less support for debugging (albeit with greater ability for fine tuning machine-to-machine communication than XML WebServices).
Most developers do not need fine tuning of communication, however, making XML WebServices the most commonly used technique by far. XML WebServices are easy to create, debug and consume from a Visual Basic 2005 application. Recreating the ActiveX EXE functionality in an XML WebService involves creating web service methods for each function you want to expose to the calling application, then upgrading or rewriting the functions from the original Visual Basic 6 ActiveX EXE into the body of each webservice method. For an overview of how to create an XML WebService in Visual Basic 2005, see this article:
If your ActiveX EXE cleanly separates functionality into discrete components, one very effective strategy is to separate the code into several Visual Basic 6 DLLs, and then use standard COM/.NET interop to wrap a web service around the Visual Basic 6 code. Each individual web service and the Visual Basic 6 code behind it could then be migrated to Visual Basic 2005 as needed, rather than all at once.
Visual Basic 2005 has great support for building multi-threaded applications, with built-in language features and debugging capabilities specifically designed to make working with multiple threads simple. If your Visual Basic 6 ActiveX EXE relies on code running on a separate thread, this behavior can be easily recreated in Visual Basic 2005. For a good overview of Multi-threading in Visual Basic 2005, see
Creating an executable that also acts as a library
Visual Basic 6 ActiveX EXEs could be used as a standalone executable or as a code library. Visual Basic 2005 does not support creating applications with a dual behavior—applications can either be an executable or a DLL, not both. These best way to achieve the same result in Visual Basic 2005 is to create two projects—an executable and a DLL. Move the reusable code and business logic into the DLL, and use the executable to call the methods in the DLL.
Is upgrading your ActiveX EXEs is necessary? It may not be: If you have stable, solid code, you no longer have to upgrade it all to Visual Basic 2005 to utilize that functionality from .NET applications. In addition, you are no longer restricted to adding new functionality with Visual Basic 6: now, you can modernize ActiveX EXEs using Visual Basic 2005 without upgrading the entire code base to Visual Basic 2005.
The recently released Interop Forms Toolkit allows developers to call Visual Basic 2005 Windows Forms from an ActiveX EXE. In addition, Visual Basic 2005 makes COM interop easier, and the process of invoking classes in a Visual Basic 6 ActiveX EXE is now a straightforward and easy-to-accomplish task.
Let's get started by looking at the sample application supplied with this article. First we'll need to make sure your machine has all the necessary prerequisites:
- You will need to have Visual Studio 2005 or Visual Basic Express installed.
- You will also need to install Visual Basic 6, with the latest service pack (SP6 at the time of writing).
- After installing the above applications, install the Visual Basic Interop Form Toolkit, which can be downloaded from here.
One of the useful features of Visual Basic is that both Visual Basic 6 and Visual Basic 2005 can installed on the same machine, and both development environments can run side-by-side on the same machine at the same time without interfering with each other. The order of installation doesn't matter: You can install Visual Basic 6 before or after installing Visual Basic 2005.
After installing the prerequisites, install the sample files to a directory on your local hard disk. After installing the sample, you will see it contains two folders: the VB6 folder contains the Visual Basic 6 components, and the VB2005 folder contains the Visual Basic 2005 components. Together these components create a simple application that counts to 100 showing the count in a progress bar, using events to reflect the count in the calling application. Later in this article, I will extend the application to enable the ActiveX EXE to be used from Visual Basic 2005, but for now let's see how the application is put together.
The sample is composed from three components—the client is a Visual Basic 6 executable named "ClientVB6," which invokes a class in a Visual Basic 6 ActiveX EXE named "CountAxExeVB6.exe," which itself loads an Interop Form from a Visual Basic 2005 class library named "CountVB2005.dll." To run the application, we need to first compile each component, starting at the top of the dependency tree—the Visual Basic 2005 component, followed by the ActiveX EXE, then finally the Visual Basic 6 client.
- Compile the Visual Basic 2005 DLL by opening the solution \VB2005\CountVB2005.sln, and choosing the menu item Build|Build CountVB2005
- Compile the Visual Basic 6 ActiveX EXE component by opening the project \VB6\CountAxExeVB6.vbp, and choosing the menu item File|Make CountAxExeVB6.exe.
- Compile the Visual Basic 6 client by opening the project \VB6\ClientVB6.vbp, and choosing the menu item File|Make ClientVB6.exe.
- Close all instances of the Visual Basic 6 and Visual Basic 2005 development environments choosing to save changes if prompted.
The application can be run in two ways. First we'll invoke the ActiveX EXE as a class library from the client. Then we'll invoke the ActiveX EXE as a standalone application.
- Double click the file \VB6\ClientVB6.exe to invoke the ActiveX EXE as a code library. The client application opens. Clicking the Count button opens a new form that counts to 100, updating a progress bar and a counter on the original form.
Figure 2. Progress bar and counter
- Double click the file \VB6\CountAxExe.exe to run the ActiveX EXE as an executable. The application counts to 100, the progress bar updates and the application exits.
Figure 3. The .exe component running as an executable
What's Going On
Although this application performs a simple task, there is a lot going on underneath the surface.
When you run the file ClientVB6.exe, the client executable creates an instance of the class clsCount within the ActiveX EXE CountAxExe.exe and invokes the Count method to begin counting. The Count method creates an instance of the Visual Basic 2005 form frmCount using the Interop Forms toolkit. This form raises events back to the ActiveX EXE, which itself raises events back to the client.
When you run the file CountAxExe.exe, the application invokes the Visual Basic 2005 form as before, but since the CountAxExe ActiveX EXE is acting as an executable, no message is passed back to any client.
The sample demonstrates how an ActiveX EXE can act as both an executable and as a class library.
Understanding the Sample
Let's look at how the sample is constructed starting with the client application.
- Open the client project in Visual Basic 6 by double clicking on the file \VB6\ClientVB6.vbp.
- Notice the project contains one form frmClient, which contains a command button for starting the count and a label for displaying the count progress.
Figure 4. frmClient project opened in Visual Basic 6
- Open the code window by double clicking on the Count button. The code is simple, it creates an instance of the ActiveX EXE clsCount class, and calls the DoCount Method.
Private Sub btnCount_Click() 'Create an instance of the ActiveX EXE class 'Invoke the DoCount method Set MyAxExeClass = New clsCount MyAxExeClass.DoCount End Sub
- The CounterChangeEvent is raised whenever the count is updated. The event procedure updates the label caption to show the latest count value.
Private Sub MyAxExeClass_CounterChangeEvent(ByVal lngCount As Long) 'Update the label caption to reflect the current count Me.lblDisplay.Caption = lngCount End Sub
- Now let's look inside the ActiveX EXE. Open the project in Visual Basic 6 by double clicking on the project \VB6\CountAxExeVB6.vbp.
- Notice this project has two files. The modAxExeMain module contains a sub main that invokes the DoCount method if the ActiveX EXE is being run as an executable.
Private MyClass As clsCount Sub Main() ' Check if we are being invoked as a class library or standalone ' executable by looking at the Command$. ' If the Command$ is -Embedding then we are being used as a class ' library. If we are being invoked as an executable then call the ' DoCount method If Command$ <> "-Embedding" Then Set MyClass = New clsCount MyClass.DoCount End If End Sub
- The second file clsCount contains the DoCount method which creates an instance of the Visual Basic 2005 frmCount InteropForm and starts the count. If the application is being run as a standalone EXE, it waits for the form to close before continuing. This is important because otherwise the code would finish and tear down the form before the count is done.
' Create an instance of the VB2005 InteropForm ' and invoke the DoCount method Set MyForm = New CountVB2005.frmCount MyForm.Show vbModeless MyForm.DoCount ' If this is a Standalone application, then ' wait for form to close If Command$ <> "-Embedding" Then While Not MyForm.IsFormDisposed DoEvents Wend MsgBox "Total count is " & m_lngCount End If
- The event CounterChange hooks the event from Visual Basic 2005 and re-raises it to the client application
Private Sub MyForm_CounterChange(ByVal lngCount As Long) m_lngCount = lngCount RaiseEvent CounterChangeEvent(lngCount) End Sub
- Finally, let's look at the Visual Basic 2005 class library that contains the InteropForm. Open the library in Visual Basic 2005 by double-clicking on the solution \VB2005\CountVB2005.sln
- Open the form frmCount. It has three controls: a timer component that updates a counter with every tick, a progress bar, and a cancel button to stop the count
Figure 5. The three control in frmCount
- Double-click the cancel button to open the code editor. In the declarations section of the form, an event is defined and made visible to Visual Basic 6 code through the InteropForms toolkit.
'Declare the event procedure and make it visible to VB6 Public Delegate Sub tagCounterChange(ByVal intCount As Integer) <InteropFormEvent()> _ Public Event CounterChange As tagCounterChange
- The progress bar is updated, and the event is fired each time the timer ticks. When the progress bar gets to the maximum, the form is closed
Private Sub tmr_Tick(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles tmr.Tick 'Increase counter by one and update progress bar 'Raise an event with the updated counter m_intCount += 1 If m_intCount <= Me.ProgressBar1.Maximum Then 'Update the progress bar and raise an event Me.ProgressBar1.Value = m_intCount RaiseEvent CounterChange(m_intCount) Else 'When the counter gets above the maxiumum 'then stop and close the form Me.tmr.Enabled = False Me.Close() End If End Sub
The sample shows how you can add a Visual Basic 2005 form to an ActiveX EXE and still keep the same functionality that makes ActiveX EXEs useful to Visual Basic 6 developers.
There are situations where you may need to invoke an ActiveX EXE from a Visual Basic 2005 application. Visual Basic 2005 cannot reference the classes in an ActiveX EXE directly because they are contained in an EXE, not a DLL. By creating a simple wrapper DLL in Visual Basic 6, however you can work around this limitation. The following steps demonstrate how to use classes in the CountAxExeVB6.exe ActiveX EXE from a Visual Basic 2005 Windows application.
- Start Visual Basic 6, and create a new ActiveX DLL.
- Add a reference to the CountAxExeVB6.exe ActiveX EXE.
- Name the project prjWrapper, and the default class clsWrapper.
- Open clsWrapper in the code editor to add the following code which creates an instance of the clsCount class, invokes the DoCount method and raises any events back to the calling application.
Option Explicit Public WithEvents MyClass As CountAxExeVB6.clsCount Public Event CounterChange(ByVal lngCount As Long) Function DoCount() Set MyClass = New CountAxExeVB6.clsCount MyClass.DoCount End Function Private Sub MyClass_CounterChangeEvent(ByVal lngCount As Long) RaiseEvent CounterChange(lngCount) End Sub
Figure 6. Editing the clsWrapper in the code editor
- Save the project and compile the DLL by choosing the menu item File|Make prjWrapper.dll.
- Close the Visual Basic 6 development environment.
- Start Visual Basic 2005, and create a new Windows Application.
- Add a reference to the COM object prjWrapper by choosing the menu item Project|Add Reference, and selecting the prjWrapper component
- Add a label and a command button onto the default form
Figure 7. Add a label and command button to the default form
- Double click on the command button to open the code editor. Add the following code which invokes the ActiveX EXE through the wrapper class and updates the label on the form each time the CounterChange event fires:
Public Class Form1 Dim WithEvents Wrap As New prjWrapper.clsWrapper Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click Wrap = New prjWrapper.clsWrapper Wrap.DoCount() End Sub Private Sub Wrap_CounterChange(ByVal lngCount As Integer) _ Handles Wrap.CounterChange Me.Label1.Text = lngCount End Sub End Class
- Press F5 to run the application, and click the command button. You will see the counter form open, count to 100, and update the label on the Visual Basic 2005 form.
This technique demonstrates how to use a Visual Basic 6 ActiveX Exe from a Visual Basic 2005 application.
In this article we looked at Visual Basic 6 ActiveX EXEs—techniques for bridging and extending functionality with Visual Basic 2005 Interop forms. We also discussed how to use classes in a Visual Basic 6 EXE from Visual Basic 2005.
Ed Robinson co-authored "Upgrading Visual Basic 6.0 to Visual Basic .NET," "Security for Visual Basic .NET," and numerous technology articles. Ed is the CIO for Intergen Ltd—one of New Zealand's most prominent Microsoft Gold Certified Partners.