We’ve worked with several AVR Classic customers lately helping them resolve challenges with their legacy Classic apps. During this work, we’ve come to the opinion that integrating AVR for .NET with AVR Classic is not only a great way to solve AVR Classic-imposed challenges and limitations, but it’s also a way to start replacing parts of your AVR Classic applications with AVR for .NET. Many AVR Classic applications are quite large and complex and rewriting them from the ground up isn’t doable–at least quickly. But over time, incrementally replacing parts of them with AVR for .NET may be the key to clawing your way out of COM prison.
Be sure to understand that this article isn’t about launching .NET EXEs with AVR’s OSExec operation. While you can achieve a modest level of interoperability with by launching an EXE with OSExec, you’re still dealing with two distinct processes that don’t really interoperate with each other. With this article’s techniques, you’ll have a single (started by AVR Classic), that uses the .NET binary just as it would an ActiveX control. You’ll be able to call .NET methods, get results back from .NET functions, and read and write .NET properties.
This article provides the keys for integrating AVR for .NET with AVR Classic. While the solution provided here is an overly-simple, academic example, with just a little more effort you can create powerful DLLs with AVR for .NET to provide services such as these (and many more) for AVR Classic:
- Integrate Active Directory with the app
- Provide SQL Server access
- Send email
- Make HTTP requests
- Generate or consume Json data
- Add new Windows forms that use any of .NET’s Windows controls
.NET provides native facilities to all of those things and many others.
To be able to follow the instructions in this article, you’ll need both AVR Classic and AVR for .NET installed on your developer PC. If you don’t yet have AVR for .NET, you can download a trial copy here.
Visual Studio setup
To consume a .NET binary (either a DLL or an EXE ) you need to register that binary with .NET’s Regasm utility. Regasm is a command line utility and is installed along with Visual Studio .NET–but it’s a little hard to find. Make it easy on yourself and use the instructions in this ASNA TechHub article to make Regasm easily available. Don’t continue until you can launch the .NET Dev Prompt from Visual Studio and see that RegAsm works. To test it, just type regasm
with command prompt displayed and press enter. You should see its help listing.
An AVR for .NET Windows app with two forms
This article shows a very simple interoperability example. It features a .NET program that has two Windows forms. Form1
shows Form2
. This is a free-standing program, an EXE, and the intent is for it to either be able to run by itself or consumed directly AVR Classic. You could also create a DLL and consume it directly from AVR Classic. If there is enough demand, we’ll cover that in more detail later (but it’s pretty much the exact process explained here).
Don’t let the simpleness of this example’s forms be offputting. They were kept simple to not let their complexity obfuscate the concept of COM/.NET interoperability. These forms could very easily be performing very complex operations. They could have database connections, be passed arguments, and generally do anything that you can do it .NET.
When it’s running on its own, the AVR for .NET program presents itself as shown below in Figure 1a.
Form1
‘s code
1 2 3 4 5 6 7 8 9 |
BegSr buttonShow<code>Form2</code>_Click Access(*Private) Event(*this.buttonShow<code>Form2</code>.Click) DclSrParm sender Type(*Object) DclSrParm e Type(System.EventArgs) DclFld f2 Type(<code>Form2</code>) New() f2.ShowDialog() EndSr |
Form2
‘s code
1 2 3 4 5 6 7 |
BegSr buttonClose_Click Access(*Private) Event(*this.buttonClose.Click) DclSrParm sender Type(*Object) DclSrParm e Type(System.EventArgs) *This.Close() EndSr |
Figure 1b. The click event handlers in the AVR for .NET example shown in Figure 1a.
As written above, the AVR for .NET example runs on its own. When you need to share .NET forms with COM, this is a good approach. You can easily use all of .NET’s debugging capabilities to ensure the forms are working exactly as expected and then surface what’s necessary from the project to COM.
While the code above makes the app run, the app isn’t quite ready to share with COM. We need just a little more code. To surface a method to COM to display Form1
, the .NET project needs the ComBridge
class, shown below in Figure 1c.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Using System.Runtime.InteropServices BegClass ComBridge Access(*Public) + Attributes(ComVisible(*True), + ClassInterface(ClassInterfaceType.AutoDual)) BegSr Form1_Show Access(*Public) Attributes(ComVisible(*True)) DclFld f Type(Form1) New() f.ShowDialog() EndSr EndClass |
Figure 1c. The ComBridge
class that surfaces methods (and optionally, properties) from the .NET project to COM.
The ComBridge
class does a couple of things:
- It marks the
ComBridge
class itself with the ComVisible and ClassInterface attributes necessary to surface the class to COM. - It marks the
Form1
_Show method with the ComVisible attribute to make the method visible to COM.
System.Runtime.InteropServices
namespace (and the Using
statement at the top of the ComBridge
class makes that namespace available).
ComBridge
defines what components of the .NET project are made available to COM (there isn’t anything magic about the ComBridge
name; the class could have any valid class name). As you’ll soon see, this ComBridge
class is visible to COM, but the form classes themselves (classes Form1
and Form2
in this project) are not directly available to COM. The intent with the ComBridge
class is to harness those elements of the .NET project necessary for COM to use those elements.
You could also apply the ComVisible and ClassInterface attributes directly in the Form1
and Form2
classes, but the ComBridge
class helps provide a clear separation of concerns–clearly identifying what parts of the project are visible to COM. While this example’s ComBridge
classes surfaces only one method, others may surface several methods and/or properties (which in turn reveal other parts of the .NET program).
After you compile the .NET project, you need to register it for COM use with RegAsm as discussed in the previous section and shown below in Figure .

1 2 |
regasm /tlb /codebase <EXE or DLL name> |
The /tlb
and /codebase
are very important. As mentioned in this article, Visual Studio needs to be run as an administrator to launch RegAsm.
In .NET, both EXEs and DLLs are simply assemblies–which is essentially one or more classes compiled as a .NET binary. You can use this technique with both .NET free-standing EXEs and DLLs.
With the EXE (or DLL) compiled and registered, you’re ready to use it from AVR Classic.
An AVR Classic app to consume the .NET EXE
To use the RegAsm-registered .NET binary from AVR Classic, set a reference to the binary in a new (or an existing) AVR Classic project. In this case, the binary’s name is DotNetWinForms. It is highlighted in AVR Classic’s Reference shown below in Figure 2a:

Form1
_Show() method declared in Figure 1c, but you can also see other methods Figure 1c doesn’t declare. These are intrinsic methods that .NET provides and can generally be ignored when consuming the .NET object from COM.
The bottom portion of the Object Browser shows that the .NET object should be declared as:
1 2 |
DclFld x Type(DotNetWinForms.ComBridge) |
dnwf
. The meager code in the AVR Classic example is shown below in Figure 2c. It is only one button click event handler and it calls the object’s Form1
_Show method.
1 2 3 4 5 6 7 |
DclFld dnwf DotNetWinForms.<code>ComBridge BEGSR buttonShowDotNETform Click DclFld dnwf Type(DotNetWinForms.ComBridge) dnwf.Form1_Show() ENDSR |
Form1
_Show method.
When the AVR Classic runs (as shown below in Figure 2d), and when its button is clicked, the AVR for .NET Form1
is displayed. ComBridge effectively provides a gateway into the .NET app. Even though nothing about Form2
is surfaced to COM, because its use is encapsulated in the .NET app, it is displayed as it should be. In this case, Form1_Show
isn’t a function (and therefore doesn’t return a value), but if it did that value would be directly available to AVR Classic. If the ComBridge
had surfaced any properties from the .NET app those would also be directly available to AVR Classic.

Get to it!
The example proves that with just a little elbow grease, you can build great components, including full Windows forms, for AVR Classic with AVR for .NET. This effectively harnesses the full power of .NET for your AVR Classic apps. It also provides the opportunity for AVR Classic shops:- Start learning .NET with a concrete purpose
- Start chipping away at obsolete third-party dependencies and replacing them AVR for .NET counterparts
- Start replacing their AVR Classic one chunk at a time