There and Back Again: Accessing VO components from .NET and vice versa
An examination of how to use VO (Win32) and .NET together within an application.
Introduction
.NET is playing an ever-growing part of current application development for Windows. An important question for us as developers using VO, with a large amount of existing code, is how we move forward and embrace .NET without abandoning what we have now. The aim of this session is to examine some of the options we have to address that question.
There are two parts to this session. The first part demonstrates how parts of your VO application can be made visible to .NET by incorporating it in a COM component. We create a sample VO COM component and access it from a .NET application. In the second part of this session we examine how VO applications can make use of managed .NET components. The .NET runtime allows any COM-aware clients to access .NET components through "COM Interop", using tools provided as part of the .NET framework. We create a simple .NET component and then walk through the steps to register the component for use by our VO application.
When we refer to VO in this session we are talking about Visual Object 2.7 for the 32 bit Windows environment. VO.NET is currently under development and being a native .NET language falls into the .NET side of the discussion in this paper. When VO.NET is released it should be possible to use it in place of C# in the examples contained here.
Creating a COM component in VO
The simplest way to create a COM component in VO, if you are unfamiliar with the process, is to open the New Application gallery, go to the OLE Server tab, and choose “OLE Inproc Server”:

This sample creates a class called SimpleAutoServer that inherits from AutoServer. For our purposes we can delete this class and create one of our own:
CLASS MyVOAutoServer INHERIT AutoServer
METHOD AddNumbers(x,y) CLASS MyVOAutoServer
RETURN x + y
METHOD UpdateString(c) CLASS MyVOAutoServer
RETURN c + " from VO"
METHOD RetrieveLogic() CLASS MyVOAutoServer
RETURN TRUE
In addition to the class code there is also a global variable, an Init procedure and a few DEFINEs. The DEFINEs are extraneous and can be deleted.
The global variable is typed as SimpleAutoServer. Since we have created our own class we can change this reference to our class name, MyVOAutoServer. The Init procedure creates an instance of SimpleAutoServer – once again we substitute our own class name. These changes yield the following code:
GLOBAL goAutoServer AS MyVOAutoServer
PROCEDURE InitProc() _INIT 3
goAutoServer := MyVOAutoServer{}
The remaining changes required are found in the application properties. First change the executable name to something more meaningful. In this example we use MyVOComp.DLL.
Next move to the OLE Server tab. The two things to change here are the ProgId, used to identify the component, and the Automation class. The ProgId can be anything, here we use MyVOComponent.Application. The Automation class should be the class we wrote, MyVOAutoServer:
Accessing a COM component from .NET
The example of accessing a VO-authored COM component in .NET is a simple console application. We begin by creating a new project in Visual Studio, and make sure Console Application is the selected template, as seen below.

In order to make use of the COM component in the application we need to add a reference to it. When the Add Reference option is selected a dialog similar to the one below is displayed.
Our component needs to be selected from the list of COM servers:

Accepting this dialog results in a library being created, representing aspects of the COM component. The contents of this library can be viewed in the object browser:

To make use of this library the example code has to include the following line:
using MyVOAutoServerLib;
The complete code for our simple sample is included below:
using System;
using MyVOAutoServerLib;
namespace ConsoleApplication1
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("Using server...");
MyVOAutoServer o = new MyVOAutoServer();
Console.WriteLine(o.UpdateString("Hello"));
Console.WriteLine(o.AddNumbers(1,2));
}
}
}
Creating a COM component in .NET
Create new C# project in Visual Studio
In order to create a COM component for this paper we will make use of Visual Studio. When the option to create a new project is select in Visual Studio a dialog such as that shown below appears:

In this dialog we have chosen to build Class Library which is called MyNetComponent, placed in a directory called ThereAndBack.
Write a class
Pressing OK on the New Project dialog produces our project skeleton and generates som simple code to get us started, as shown below. Note that the namespace assigned is the same as the project name specified.

Now we make some changes to this generated code to customise it for our needs. First of all, to make things clearer in this paper, we will remove the comment lines. Then rename the public class Class1 to something more appropriate, such as Application. Also, for this example we will not need a custom constructor for the class, so we remove the public Class1() member. We also add a simple member of our own for testing, call RetrieveLogic that returns a Boolean (logic). Those changes leave us with this code:
using System;
namespace MyNetComponent
{
public class Application
{
public bool RetrieveLogic()
{
return true;
}
}
}
Register the output file
Because the purpose of this exercise is to produce a COM component, we need to tell Visual Studio that we want the output of this project to be registered on the machine as a COM component. This is done by calling up the project properties and moving to the Configuration properties. One of the options in the Outputs section of the Configuration properties is call “Register for COM Interop”. This should be set True so that Visual Studio will register the output file for use with COM, as seen below:

When you want to register this component on a machine other than your development machine you can use the REGASM utility to do the job.
The class interface
If the project is built at this stage MyNetComponent.DLL and MyNetComponent.TLB are beneath the project’s BIN directory. The component is also registered for COM on the machine. However by default the Visual Studio type library tools do not automatically include the methods in the default COM class interface. This means the methods are only accessible late bound. In order to be able to use the COM component early bound you need to explicitly instruct the tools export the public members (methods). The first way we can do this is by including the line
[ClassInterface(ClassInterfaceType.AutoDual)]
before the public class Application line.
Now this ClassInterface facility is provided by the .NET InteropServices and for our program to compile correctly we also need to include:
using System.Runtime.InteropServices;
//after the using System line. So our complete
//code now looks like this:
using System;
using System.Runtime.InteropServices;
namespace MyNetComponent
{
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Application
{
public bool RetrieveLogic()
{
return true;
}
}
}
With this code when the project is built the output will include information about the public properties and methods so that the component can be used early bound.
Accessing a .NET COM component from VO
In Visual Objects the .NET COM component can be accessed like other COM components.
Late bound
When a COM component is late bound the information about the properties and methods is determined at runtime.
Here is the VO code to create a late bound version of our example .NET COM component:
LOCAL oLate AS OBJECT
LOCAL x AS USUAL
oLate := OLEAutoObject{"MyNetComponent.Application"}
IF oLate:fInit
x := oLate:RetrieveLogic()
InfoBox{,"Late bound",AsString(x)}:show()
ELSE
ErrorBox{,"Could not create late bound component"}:show()
ENDIF
Note the parameter passed to OLEAutoObject is the COM ProgId which identifies the component we want to instantiate. The ProgId of our .NET sample is made up from the namespace (MyNetComponent) and the class name (Application) which yield MyNetComponent.Application.
Early bound
To use a COM component early bound in VO code is generated from the component. This is done by selecting Automation Server from the VO Tools menu.

As you can see from the diagram MyNetComponent appears in the list of available servers, courtesy of the registration performed by Visual Studio when we built the component. If you highlight the server entry and then press the Show Interfaces button the interfaces listbox, which was empty, now has an entry called _Application. The actually comes from our Application class in our .NET component – VO adds the underscore at the front to avoid a name conflict with VO’s own Application class. If you click on the _Application interface the Class name field, which was empty, is filled with interface name. You can change this class name if you desire.
Clicking on the Generate source button instructs VO to interrogate the component and produce class code in the current module.
In addition to a RetrieveLogic() method arising from the member we wrote in C# there are some other methods in the VO generated code: ToString, Equals, GetHashCode, GetType. These methods appear because the default class interface of the component actually inherits from .NET’s System.Object and these methods come from that class.
The component can be used early bound as follows:
LOCAL oEarly AS OBJECT
LOCAL x AS USUAL
oEarly := _Application{}
IF oEarly:fInit
x := oEarly:RetrieveLogic()
InfoBox{,"Early bound",AsString(x)}:show()
ELSE
ErrorBox{,"Could not create early bound component"}:show()
ENDIF
Handling Data
The standard data types can be passed to and from the .NET component. For example we can add two methods to our sample component, one to handle numbers, another to handle a string:
public uint AddNumbers(uint x, uint y)
{
return x+y;
}
public string UpdateString(string c)
{
return c + " from .NET";
}
These can then be successfully called from the VO application, passing and receiving data:
x := oLate:AddNumbers(40,2)
InfoBox{,"Late Bound",AsString(x)}:show()
x := oLate:UpdateString("Here is a string")
InfoBox{,"Late Bound",AsString(x)}:show()
Note that any methods of the component that are expecting to receive a value such as a .NET object cannot be easily called from the VO application. It is simpler to keep any creation of .NET objects within the component, so it may be necessary to create extra methods form the component that can perform these tasks. The VO application can then call these worker methods to handle any .NET objects.
Another look at the class interface
Earlier the ClassInterface feature was used to make the public attributes of the component visible to calling code. A problem with the ClassInterfaceType.AutoDual is that while it does create a public interface it does not guarantee that the items within the interface will have the same order each time a new build of the component is produced. In other words, it automatically creates the interface from the code and if the code is restructured the order of the methods within the interface may change. This unfortunately is not the way well-behaved COM component are supposed to work, where from one version to the next the interface should only be added to.
So to create a well-behaved COM component the interface must retain its order between versions with new entries adding to the end.
To achieve this in .NET we need to specify the interface explicitly. This is somewhat similar to the declaration of methods in a VO class.
Firstly we need to instruct .NET that we do not want it to generate an interface since we are taking over that role. We do this by replacing the
[ClassInterface(ClassInterfaceType.AutoDual)]
with
[ClassInterface(ClassInterfaceType.None)]
Next we have to explicitly define the interface we want:
public interface IApplication
{
bool RetrieveLogic();
uint AddNumbers(uint x,uint y);
string UpdateString(string c);
}
This definition is placed within the namespace.
Lastly we need to say that our Application class is going to use the interface IApplicaton by updating the class definition:
public class Application:IApplication
The full source for our .NET COM sample is now:
using System;
using System.Runtime.InteropServices;
namespace MyNetComponent
{
[ClassInterface(ClassInterfaceType.None)]
public class Application:IApplication
{
public bool RetrieveLogic()
{
return true;
}
public uint AddNumbers(uint x, uint y)
{
return x+y;
}
public string UpdateString(string c)
{
return c + " from .NET";
}
}
public interface IApplication
{
bool RetrieveLogic();
uint AddNumbers(uint x,uint y);
string UpdateString(string c);
}
}
Changing ProgId and GUID
You can explicitly define the ProgId and GUID to be used for the COM component you are creating.
To do this include lines like the following before the class definition:
[GuidAttribute("1C15D9C7-A3EF-3485-0000-156524C461A1"),
ProgId("MyNetComponent.Manager")]
Another Example
Using techniques similar to those presented in this paper, Ed Richard took a C# application used to display popup windows from the taskbar, converted to a COM component accessible from VO. Details of how he did this, including source code, is available at http://www.sdn.nl/Display.aspx?id=1522.